blob: 452a2ac4eec8ca58d4083b05dc4756224bb7f95c [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 *
Pierre Ynard31910572007-10-10 21:22:05 -070018 * Pierre Ynard : export userland ND options
19 * through netlink (RDNSS support)
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 * Lars Fenneberg : fixed MTU setting on receipt
21 * of an RA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * Janos Farkas : kmalloc failure checks
23 * Alexey Kuznetsov : state machine reworked
24 * and moved to net/core.
25 * Pekka Savola : RFC2461 validation
26 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
27 */
28
29/* Set to 3 to get tracing... */
30#define ND_DEBUG 1
31
32#define ND_PRINTK(fmt, args...) do { if (net_ratelimit()) { printk(fmt, ## args); } } while(0)
33#define ND_NOPRINTK(x...) do { ; } while(0)
34#define ND_PRINTK0 ND_PRINTK
35#define ND_PRINTK1 ND_NOPRINTK
36#define ND_PRINTK2 ND_NOPRINTK
37#define ND_PRINTK3 ND_NOPRINTK
38#if ND_DEBUG >= 1
39#undef ND_PRINTK1
40#define ND_PRINTK1 ND_PRINTK
41#endif
42#if ND_DEBUG >= 2
43#undef ND_PRINTK2
44#define ND_PRINTK2 ND_PRINTK
45#endif
46#if ND_DEBUG >= 3
47#undef ND_PRINTK3
48#define ND_PRINTK3 ND_PRINTK
49#endif
50
51#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <linux/errno.h>
53#include <linux/types.h>
54#include <linux/socket.h>
55#include <linux/sockios.h>
56#include <linux/sched.h>
57#include <linux/net.h>
58#include <linux/in6.h>
59#include <linux/route.h>
60#include <linux/init.h>
61#include <linux/rcupdate.h>
62#ifdef CONFIG_SYSCTL
63#include <linux/sysctl.h>
64#endif
65
Thomas Graf18237302006-08-04 23:04:54 -070066#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/if_arp.h>
68#include <linux/ipv6.h>
69#include <linux/icmpv6.h>
70#include <linux/jhash.h>
71
72#include <net/sock.h>
73#include <net/snmp.h>
74
75#include <net/ipv6.h>
76#include <net/protocol.h>
77#include <net/ndisc.h>
78#include <net/ip6_route.h>
79#include <net/addrconf.h>
80#include <net/icmp.h>
81
Pierre Ynard31910572007-10-10 21:22:05 -070082#include <net/netlink.h>
83#include <linux/rtnetlink.h>
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#include <net/flow.h>
86#include <net/ip6_checksum.h>
87#include <linux/proc_fs.h>
88
89#include <linux/netfilter.h>
90#include <linux/netfilter_ipv6.h>
91
92static struct socket *ndisc_socket;
93
94static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
95static int ndisc_constructor(struct neighbour *neigh);
96static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
97static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
98static int pndisc_constructor(struct pneigh_entry *n);
99static void pndisc_destructor(struct pneigh_entry *n);
100static void pndisc_redo(struct sk_buff *skb);
101
102static struct neigh_ops ndisc_generic_ops = {
103 .family = AF_INET6,
104 .solicit = ndisc_solicit,
105 .error_report = ndisc_error_report,
106 .output = neigh_resolve_output,
107 .connected_output = neigh_connected_output,
108 .hh_output = dev_queue_xmit,
109 .queue_xmit = dev_queue_xmit,
110};
111
112static struct neigh_ops ndisc_hh_ops = {
113 .family = AF_INET6,
114 .solicit = ndisc_solicit,
115 .error_report = ndisc_error_report,
116 .output = neigh_resolve_output,
117 .connected_output = neigh_resolve_output,
118 .hh_output = dev_queue_xmit,
119 .queue_xmit = dev_queue_xmit,
120};
121
122
123static struct neigh_ops ndisc_direct_ops = {
124 .family = AF_INET6,
125 .output = dev_queue_xmit,
126 .connected_output = dev_queue_xmit,
127 .hh_output = dev_queue_xmit,
128 .queue_xmit = dev_queue_xmit,
129};
130
131struct neigh_table nd_tbl = {
132 .family = AF_INET6,
133 .entry_size = sizeof(struct neighbour) + sizeof(struct in6_addr),
134 .key_len = sizeof(struct in6_addr),
135 .hash = ndisc_hash,
136 .constructor = ndisc_constructor,
137 .pconstructor = pndisc_constructor,
138 .pdestructor = pndisc_destructor,
139 .proxy_redo = pndisc_redo,
140 .id = "ndisc_cache",
141 .parms = {
142 .tbl = &nd_tbl,
143 .base_reachable_time = 30 * HZ,
144 .retrans_time = 1 * HZ,
145 .gc_staletime = 60 * HZ,
146 .reachable_time = 30 * HZ,
147 .delay_probe_time = 5 * HZ,
148 .queue_len = 3,
149 .ucast_probes = 3,
150 .mcast_probes = 3,
151 .anycast_delay = 1 * HZ,
152 .proxy_delay = (8 * HZ) / 10,
153 .proxy_qlen = 64,
154 },
155 .gc_interval = 30 * HZ,
156 .gc_thresh1 = 128,
157 .gc_thresh2 = 512,
158 .gc_thresh3 = 1024,
159};
160
161/* ND options */
162struct ndisc_options {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800163 struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
164#ifdef CONFIG_IPV6_ROUTE_INFO
165 struct nd_opt_hdr *nd_opts_ri;
166 struct nd_opt_hdr *nd_opts_ri_end;
167#endif
Pierre Ynard31910572007-10-10 21:22:05 -0700168 struct nd_opt_hdr *nd_useropts;
169 struct nd_opt_hdr *nd_useropts_end;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170};
171
172#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
173#define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR]
174#define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO]
175#define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END]
176#define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
177#define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
178
179#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
180
181/*
182 * Return the padding between the option length and the start of the
183 * link addr. Currently only IP-over-InfiniBand needs this, although
184 * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
185 * also need a pad of 2.
186 */
187static int ndisc_addr_option_pad(unsigned short type)
188{
189 switch (type) {
190 case ARPHRD_INFINIBAND: return 2;
191 default: return 0;
192 }
193}
194
195static inline int ndisc_opt_addr_space(struct net_device *dev)
196{
197 return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
198}
199
200static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
201 unsigned short addr_type)
202{
203 int space = NDISC_OPT_SPACE(data_len);
204 int pad = ndisc_addr_option_pad(addr_type);
205
206 opt[0] = type;
207 opt[1] = space>>3;
208
209 memset(opt + 2, 0, pad);
210 opt += pad;
211 space -= pad;
212
213 memcpy(opt+2, data, data_len);
214 data_len += 2;
215 opt += data_len;
216 if ((space -= data_len) > 0)
217 memset(opt, 0, space);
218 return opt + space;
219}
220
221static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
222 struct nd_opt_hdr *end)
223{
224 int type;
225 if (!cur || !end || cur >= end)
226 return NULL;
227 type = cur->nd_opt_type;
228 do {
229 cur = ((void *)cur) + (cur->nd_opt_len << 3);
230 } while(cur < end && cur->nd_opt_type != type);
231 return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
232}
233
Pierre Ynard31910572007-10-10 21:22:05 -0700234static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
235{
236 return (opt->nd_opt_type == ND_OPT_RDNSS);
237}
238
239static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
240 struct nd_opt_hdr *end)
241{
242 if (!cur || !end || cur >= end)
243 return NULL;
244 do {
245 cur = ((void *)cur) + (cur->nd_opt_len << 3);
246 } while(cur < end && !ndisc_is_useropt(cur));
247 return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL);
248}
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
251 struct ndisc_options *ndopts)
252{
253 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
254
255 if (!nd_opt || opt_len < 0 || !ndopts)
256 return NULL;
257 memset(ndopts, 0, sizeof(*ndopts));
258 while (opt_len) {
259 int l;
260 if (opt_len < sizeof(struct nd_opt_hdr))
261 return NULL;
262 l = nd_opt->nd_opt_len << 3;
263 if (opt_len < l || l == 0)
264 return NULL;
265 switch (nd_opt->nd_opt_type) {
266 case ND_OPT_SOURCE_LL_ADDR:
267 case ND_OPT_TARGET_LL_ADDR:
268 case ND_OPT_MTU:
269 case ND_OPT_REDIRECT_HDR:
270 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
271 ND_PRINTK2(KERN_WARNING
272 "%s(): duplicated ND6 option found: type=%d\n",
273 __FUNCTION__,
274 nd_opt->nd_opt_type);
275 } else {
276 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
277 }
278 break;
279 case ND_OPT_PREFIX_INFO:
280 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700281 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
283 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800284#ifdef CONFIG_IPV6_ROUTE_INFO
285 case ND_OPT_ROUTE_INFO:
286 ndopts->nd_opts_ri_end = nd_opt;
287 if (!ndopts->nd_opts_ri)
288 ndopts->nd_opts_ri = nd_opt;
289 break;
290#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700292 if (ndisc_is_useropt(nd_opt)) {
293 ndopts->nd_useropts_end = nd_opt;
294 if (!ndopts->nd_useropts)
295 ndopts->nd_useropts = nd_opt;
296 } else {
297 /*
298 * Unknown options must be silently ignored,
299 * to accommodate future extension to the
300 * protocol.
301 */
302 ND_PRINTK2(KERN_NOTICE
303 "%s(): ignored unsupported option; type=%d, len=%d\n",
304 __FUNCTION__,
305 nd_opt->nd_opt_type, nd_opt->nd_opt_len);
306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
308 opt_len -= l;
309 nd_opt = ((void *)nd_opt) + l;
310 }
311 return ndopts;
312}
313
314static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
315 struct net_device *dev)
316{
317 u8 *lladdr = (u8 *)(p + 1);
318 int lladdrlen = p->nd_opt_len << 3;
319 int prepad = ndisc_addr_option_pad(dev->type);
320 if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
321 return NULL;
322 return (lladdr + prepad);
323}
324
325int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
326{
327 switch (dev->type) {
328 case ARPHRD_ETHER:
329 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
330 case ARPHRD_FDDI:
331 ipv6_eth_mc_map(addr, buf);
332 return 0;
333 case ARPHRD_IEEE802_TR:
334 ipv6_tr_mc_map(addr,buf);
335 return 0;
336 case ARPHRD_ARCNET:
337 ipv6_arcnet_mc_map(addr, buf);
338 return 0;
339 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700340 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return 0;
342 default:
343 if (dir) {
344 memcpy(buf, dev->broadcast, dev->addr_len);
345 return 0;
346 }
347 }
348 return -EINVAL;
349}
350
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900351EXPORT_SYMBOL(ndisc_mc_map);
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
354{
355 const u32 *p32 = pkey;
356 u32 addr_hash, i;
357
358 addr_hash = 0;
359 for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
360 addr_hash ^= *p32++;
361
362 return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd);
363}
364
365static int ndisc_constructor(struct neighbour *neigh)
366{
367 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
368 struct net_device *dev = neigh->dev;
369 struct inet6_dev *in6_dev;
370 struct neigh_parms *parms;
371 int is_multicast = ipv6_addr_is_multicast(addr);
372
373 rcu_read_lock();
374 in6_dev = in6_dev_get(dev);
375 if (in6_dev == NULL) {
376 rcu_read_unlock();
377 return -EINVAL;
378 }
379
380 parms = in6_dev->nd_parms;
381 __neigh_parms_put(neigh->parms);
382 neigh->parms = neigh_parms_clone(parms);
383 rcu_read_unlock();
384
385 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700386 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 neigh->nud_state = NUD_NOARP;
388 neigh->ops = &ndisc_direct_ops;
389 neigh->output = neigh->ops->queue_xmit;
390 } else {
391 if (is_multicast) {
392 neigh->nud_state = NUD_NOARP;
393 ndisc_mc_map(addr, neigh->ha, dev, 1);
394 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
395 neigh->nud_state = NUD_NOARP;
396 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
397 if (dev->flags&IFF_LOOPBACK)
398 neigh->type = RTN_LOCAL;
399 } else if (dev->flags&IFF_POINTOPOINT) {
400 neigh->nud_state = NUD_NOARP;
401 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
402 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700403 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 neigh->ops = &ndisc_hh_ops;
405 else
406 neigh->ops = &ndisc_generic_ops;
407 if (neigh->nud_state&NUD_VALID)
408 neigh->output = neigh->ops->connected_output;
409 else
410 neigh->output = neigh->ops->output;
411 }
412 in6_dev_put(in6_dev);
413 return 0;
414}
415
416static int pndisc_constructor(struct pneigh_entry *n)
417{
418 struct in6_addr *addr = (struct in6_addr*)&n->key;
419 struct in6_addr maddr;
420 struct net_device *dev = n->dev;
421
422 if (dev == NULL || __in6_dev_get(dev) == NULL)
423 return -EINVAL;
424 addrconf_addr_solict_mult(addr, &maddr);
425 ipv6_dev_mc_inc(dev, &maddr);
426 return 0;
427}
428
429static void pndisc_destructor(struct pneigh_entry *n)
430{
431 struct in6_addr *addr = (struct in6_addr*)&n->key;
432 struct in6_addr maddr;
433 struct net_device *dev = n->dev;
434
435 if (dev == NULL || __in6_dev_get(dev) == NULL)
436 return;
437 addrconf_addr_solict_mult(addr, &maddr);
438 ipv6_dev_mc_dec(dev, &maddr);
439}
440
441/*
442 * Send a Neighbour Advertisement
443 */
444
445static inline void ndisc_flow_init(struct flowi *fl, u8 type,
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700446 struct in6_addr *saddr, struct in6_addr *daddr,
447 int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 memset(fl, 0, sizeof(*fl));
450 ipv6_addr_copy(&fl->fl6_src, saddr);
451 ipv6_addr_copy(&fl->fl6_dst, daddr);
452 fl->proto = IPPROTO_ICMPV6;
453 fl->fl_icmp_type = type;
454 fl->fl_icmp_code = 0;
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700455 fl->oif = oif;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700456 security_sk_classify_flow(ndisc_socket->sk, fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900459static void __ndisc_send(struct net_device *dev,
460 struct neighbour *neigh,
461 struct in6_addr *daddr, struct in6_addr *saddr,
462 struct icmp6hdr *icmp6h, struct in6_addr *target,
David L Stevens14878f72007-09-16 16:52:35 -0700463 int llinfo)
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900464{
465 struct flowi fl;
466 struct dst_entry *dst;
467 struct sock *sk = ndisc_socket->sk;
468 struct sk_buff *skb;
469 struct icmp6hdr *hdr;
470 struct inet6_dev *idev;
471 int len;
472 int err;
David L Stevens14878f72007-09-16 16:52:35 -0700473 u8 *opt, type;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900474
David L Stevens14878f72007-09-16 16:52:35 -0700475 type = icmp6h->icmp6_type;
476
477 ndisc_flow_init(&fl, type, saddr, daddr,
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900478 dev->ifindex);
479
480 dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
481 if (!dst)
482 return;
483
484 err = xfrm_lookup(&dst, &fl, NULL, 0);
485 if (err < 0)
486 return;
487
488 if (!dev->addr_len)
489 llinfo = 0;
490
491 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
492 if (llinfo)
493 len += ndisc_opt_addr_space(dev);
494
495 skb = sock_alloc_send_skb(sk,
496 (MAX_HEADER + sizeof(struct ipv6hdr) +
497 len + LL_RESERVED_SPACE(dev)),
498 1, &err);
499 if (!skb) {
500 ND_PRINTK0(KERN_ERR
501 "ICMPv6 ND: %s() failed to allocate an skb.\n",
502 __FUNCTION__);
503 dst_release(dst);
504 return;
505 }
506
507 skb_reserve(skb, LL_RESERVED_SPACE(dev));
508 ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
509
510 skb->transport_header = skb->tail;
511 skb_put(skb, len);
512
513 hdr = (struct icmp6hdr *)skb_transport_header(skb);
514 memcpy(hdr, icmp6h, sizeof(*hdr));
515
516 opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
517 if (target) {
518 ipv6_addr_copy((struct in6_addr *)opt, target);
519 opt += sizeof(*target);
520 }
521
522 if (llinfo)
523 ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
524 dev->addr_len, dev->type);
525
526 hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
527 IPPROTO_ICMPV6,
528 csum_partial((__u8 *) hdr,
529 len, 0));
530
531 skb->dst = dst;
532
533 idev = in6_dev_get(dst->dev);
534 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
535
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800536 err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
537 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900538 if (!err) {
David L Stevens14878f72007-09-16 16:52:35 -0700539 ICMP6MSGOUT_INC_STATS(idev, type);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900540 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
541 }
542
543 if (likely(idev != NULL))
544 in6_dev_put(idev);
545}
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
548 struct in6_addr *daddr, struct in6_addr *solicited_addr,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900549 int router, int solicited, int override, int inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
551 struct in6_addr tmpaddr;
552 struct inet6_ifaddr *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 struct in6_addr *src_addr;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900554 struct icmp6hdr icmp6h = {
555 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
556 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 /* for anycast or proxy, solicited_addr != src_addr */
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800559 ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900560 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700562 if (ifp->flags & IFA_F_OPTIMISTIC)
563 override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 in6_ifa_put(ifp);
565 } else {
566 if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
567 return;
568 src_addr = &tmpaddr;
569 }
570
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900571 icmp6h.icmp6_router = router;
572 icmp6h.icmp6_solicited = solicited;
573 icmp6h.icmp6_override = override;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900575 __ndisc_send(dev, neigh, daddr, src_addr,
576 &icmp6h, solicited_addr,
David L Stevens14878f72007-09-16 16:52:35 -0700577 inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900578}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
581 struct in6_addr *solicit,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900582 struct in6_addr *daddr, struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 struct in6_addr addr_buf;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900585 struct icmp6hdr icmp6h = {
586 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
587 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700590 if (ipv6_get_lladdr(dev, &addr_buf,
591 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return;
593 saddr = &addr_buf;
594 }
595
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900596 __ndisc_send(dev, neigh, daddr, saddr,
597 &icmp6h, solicit,
David L Stevens14878f72007-09-16 16:52:35 -0700598 !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599}
600
601void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
602 struct in6_addr *daddr)
603{
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900604 struct icmp6hdr icmp6h = {
605 .icmp6_type = NDISC_ROUTER_SOLICITATION,
606 };
Neil Horman95c385b2007-04-25 17:08:10 -0700607 int send_sllao = dev->addr_len;
Neil Horman95c385b2007-04-25 17:08:10 -0700608
609#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
610 /*
611 * According to section 2.2 of RFC 4429, we must not
612 * send router solicitations with a sllao from
613 * optimistic addresses, but we may send the solicitation
614 * if we don't include the sllao. So here we check
615 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800616 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700617 */
618 if (send_sllao) {
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800619 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr,
620 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700621 if (ifp) {
622 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900623 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700624 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900625 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700626 } else {
627 send_sllao = 0;
628 }
629 }
630#endif
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900631 __ndisc_send(dev, NULL, daddr, saddr,
632 &icmp6h, NULL,
David L Stevens14878f72007-09-16 16:52:35 -0700633 send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
638{
639 /*
640 * "The sender MUST return an ICMP
641 * destination unreachable"
642 */
643 dst_link_failure(skb);
644 kfree_skb(skb);
645}
646
647/* Called with locked neigh: either read or both */
648
649static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
650{
651 struct in6_addr *saddr = NULL;
652 struct in6_addr mcaddr;
653 struct net_device *dev = neigh->dev;
654 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
655 int probes = atomic_read(&neigh->probes);
656
Daniel Lezcanobfeade02008-01-10 22:43:18 -0800657 if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700658 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 if ((probes -= neigh->parms->ucast_probes) < 0) {
661 if (!(neigh->nud_state & NUD_VALID)) {
662 ND_PRINTK1(KERN_DEBUG
663 "%s(): trying to ucast probe in NUD_INVALID: "
Joe Perches46b86a22006-01-13 14:29:07 -0800664 NIP6_FMT "\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 __FUNCTION__,
666 NIP6(*target));
667 }
668 ndisc_send_ns(dev, neigh, target, target, saddr);
669 } else if ((probes -= neigh->parms->app_probes) < 0) {
670#ifdef CONFIG_ARPD
671 neigh_app_ns(neigh);
672#endif
673 } else {
674 addrconf_addr_solict_mult(target, &mcaddr);
675 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
676 }
677}
678
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700679static struct pneigh_entry *pndisc_check_router(struct net_device *dev,
680 struct in6_addr *addr, int *is_router)
681{
682 struct pneigh_entry *n;
683
684 read_lock_bh(&nd_tbl.lock);
685 n = __pneigh_lookup(&nd_tbl, &init_net, addr, dev);
686 if (n != NULL)
687 *is_router = (n->flags & NTF_ROUTER);
688 read_unlock_bh(&nd_tbl.lock);
689
690 return n;
691}
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693static void ndisc_recv_ns(struct sk_buff *skb)
694{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700695 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700696 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
697 struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700699 u32 ndoptlen = skb->tail - (skb->transport_header +
700 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct ndisc_options ndopts;
702 struct net_device *dev = skb->dev;
703 struct inet6_ifaddr *ifp;
704 struct inet6_dev *idev = NULL;
705 struct neighbour *neigh;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700706 struct pneigh_entry *pneigh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 int dad = ipv6_addr_any(saddr);
708 int inc;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700709 int is_router = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 if (ipv6_addr_is_multicast(&msg->target)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900712 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 "ICMPv6 NS: multicast target address");
714 return;
715 }
716
717 /*
718 * RFC2461 7.1.1:
719 * DAD has to be destined for solicited node multicast address.
720 */
721 if (dad &&
722 !(daddr->s6_addr32[0] == htonl(0xff020000) &&
723 daddr->s6_addr32[1] == htonl(0x00000000) &&
724 daddr->s6_addr32[2] == htonl(0x00000001) &&
725 daddr->s6_addr [12] == 0xff )) {
726 ND_PRINTK2(KERN_WARNING
727 "ICMPv6 NS: bad DAD packet (wrong destination)\n");
728 return;
729 }
730
731 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900732 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 "ICMPv6 NS: invalid ND options\n");
734 return;
735 }
736
737 if (ndopts.nd_opts_src_lladdr) {
738 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
739 if (!lladdr) {
740 ND_PRINTK2(KERN_WARNING
741 "ICMPv6 NS: invalid link-layer address length\n");
742 return;
743 }
744
745 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900746 * If the IP source address is the unspecified address,
747 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 * in the message.
749 */
750 if (dad) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900751 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 "ICMPv6 NS: bad DAD packet (link-layer address option)\n");
753 return;
754 }
755 }
756
757 inc = ipv6_addr_is_multicast(daddr);
758
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800759 if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700760
761 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
762 if (dad) {
763 if (dev->type == ARPHRD_IEEE802_TR) {
Arnaldo Carvalho de Melo98e399f2007-03-19 15:33:04 -0700764 const unsigned char *sadr;
765 sadr = skb_mac_header(skb);
Neil Horman95c385b2007-04-25 17:08:10 -0700766 if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
767 sadr[9] == dev->dev_addr[1] &&
768 sadr[10] == dev->dev_addr[2] &&
769 sadr[11] == dev->dev_addr[3] &&
770 sadr[12] == dev->dev_addr[4] &&
771 sadr[13] == dev->dev_addr[5]) {
772 /* looped-back to us */
773 goto out;
774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Neil Horman95c385b2007-04-25 17:08:10 -0700776
777 /*
778 * We are colliding with another node
779 * who is doing DAD
780 * so fail our DAD process
781 */
782 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200783 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700784 } else {
785 /*
786 * This is not a dad solicitation.
787 * If we are an optimistic node,
788 * we should respond.
789 * Otherwise, we should ignore it.
790 */
791 if (!(ifp->flags & IFA_F_OPTIMISTIC))
792 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795
796 idev = ifp->idev;
797 } else {
798 idev = in6_dev_get(dev);
799 if (!idev) {
800 /* XXX: count this drop? */
801 return;
802 }
803
804 if (ipv6_chk_acast_addr(dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900805 (idev->cnf.forwarding &&
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700806 (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700807 (pneigh = pndisc_check_router(dev, &msg->target,
808 &is_router)) != NULL)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700809 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 skb->pkt_type != PACKET_HOST &&
811 inc != 0 &&
812 idev->nd_parms->proxy_delay != 0) {
813 /*
814 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900815 * sender should delay its response
816 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 * MAX_ANYCAST_DELAY_TIME seconds.
818 * (RFC2461) -- yoshfuji
819 */
820 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
821 if (n)
822 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
823 goto out;
824 }
825 } else
826 goto out;
827 }
828
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700829 is_router = !!(pneigh ? is_router : idev->cnf.forwarding);
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (dad) {
832 struct in6_addr maddr;
833
834 ipv6_addr_all_nodes(&maddr);
835 ndisc_send_na(dev, NULL, &maddr, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700836 is_router, 0, (ifp != NULL), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 goto out;
838 }
839
840 if (inc)
841 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
842 else
843 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
844
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900845 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 * update / create cache entry
847 * for the source address
848 */
849 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
850 !inc || lladdr || !dev->addr_len);
851 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900852 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 NEIGH_UPDATE_F_WEAK_OVERRIDE|
854 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700855 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 ndisc_send_na(dev, neigh, saddr, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700857 is_router,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 1, (ifp != NULL && inc), inc);
859 if (neigh)
860 neigh_release(neigh);
861 }
862
863out:
864 if (ifp)
865 in6_ifa_put(ifp);
866 else
867 in6_dev_put(idev);
868
869 return;
870}
871
872static void ndisc_recv_na(struct sk_buff *skb)
873{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700874 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700875 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
876 struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700878 u32 ndoptlen = skb->tail - (skb->transport_header +
879 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 struct ndisc_options ndopts;
881 struct net_device *dev = skb->dev;
882 struct inet6_ifaddr *ifp;
883 struct neighbour *neigh;
884
885 if (skb->len < sizeof(struct nd_msg)) {
886 ND_PRINTK2(KERN_WARNING
887 "ICMPv6 NA: packet too short\n");
888 return;
889 }
890
891 if (ipv6_addr_is_multicast(&msg->target)) {
892 ND_PRINTK2(KERN_WARNING
893 "ICMPv6 NA: target address is multicast.\n");
894 return;
895 }
896
897 if (ipv6_addr_is_multicast(daddr) &&
898 msg->icmph.icmp6_solicited) {
899 ND_PRINTK2(KERN_WARNING
900 "ICMPv6 NA: solicited NA is multicasted.\n");
901 return;
902 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
905 ND_PRINTK2(KERN_WARNING
906 "ICMPv6 NS: invalid ND option\n");
907 return;
908 }
909 if (ndopts.nd_opts_tgt_lladdr) {
910 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
911 if (!lladdr) {
912 ND_PRINTK2(KERN_WARNING
913 "ICMPv6 NA: invalid link-layer address length\n");
914 return;
915 }
916 }
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800917 if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (ifp->flags & IFA_F_TENTATIVE) {
919 addrconf_dad_failure(ifp);
920 return;
921 }
922 /* What should we make now? The advertisement
923 is invalid, but ndisc specs say nothing
924 about it. It could be misconfiguration, or
925 an smart proxy agent tries to help us :-)
926 */
927 ND_PRINTK1(KERN_WARNING
928 "ICMPv6 NA: someone advertises our address on %s!\n",
929 ifp->idev->dev->name);
930 in6_ifa_put(ifp);
931 return;
932 }
933 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
934
935 if (neigh) {
936 u8 old_flags = neigh->flags;
937
938 if (neigh->nud_state & NUD_FAILED)
939 goto out;
940
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700941 /*
942 * Don't update the neighbor cache entry on a proxy NA from
943 * ourselves because either the proxied node is off link or it
944 * has already sent a NA to us.
945 */
946 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700947 ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
Eric W. Biederman426b5302008-01-24 00:13:18 -0800948 pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) {
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700949 /* XXX: idev->cnf.prixy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700950 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700951 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 neigh_update(neigh, lladdr,
954 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
955 NEIGH_UPDATE_F_WEAK_OVERRIDE|
956 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
957 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
958 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
959
960 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
961 /*
962 * Change: router to host
963 */
964 struct rt6_info *rt;
965 rt = rt6_get_dflt_router(saddr, dev);
966 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700967 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 }
969
970out:
971 neigh_release(neigh);
972 }
973}
974
975static void ndisc_recv_rs(struct sk_buff *skb)
976{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700977 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
979 struct neighbour *neigh;
980 struct inet6_dev *idev;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700981 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 struct ndisc_options ndopts;
983 u8 *lladdr = NULL;
984
985 if (skb->len < sizeof(*rs_msg))
986 return;
987
988 idev = in6_dev_get(skb->dev);
989 if (!idev) {
990 if (net_ratelimit())
991 ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
992 return;
993 }
994
995 /* Don't accept RS if we're not in router mode */
996 if (!idev->cnf.forwarding)
997 goto out;
998
999 /*
1000 * Don't update NCE if src = ::;
1001 * this implies that the source node has no ip address assigned yet.
1002 */
1003 if (ipv6_addr_any(saddr))
1004 goto out;
1005
1006 /* Parse ND options */
1007 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
1008 if (net_ratelimit())
1009 ND_PRINTK2("ICMP6 NS: invalid ND option, ignored\n");
1010 goto out;
1011 }
1012
1013 if (ndopts.nd_opts_src_lladdr) {
1014 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1015 skb->dev);
1016 if (!lladdr)
1017 goto out;
1018 }
1019
1020 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1021 if (neigh) {
1022 neigh_update(neigh, lladdr, NUD_STALE,
1023 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1024 NEIGH_UPDATE_F_OVERRIDE|
1025 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1026 neigh_release(neigh);
1027 }
1028out:
1029 in6_dev_put(idev);
1030}
1031
Pierre Ynard31910572007-10-10 21:22:05 -07001032static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1033{
1034 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1035 struct sk_buff *skb;
1036 struct nlmsghdr *nlh;
1037 struct nduseroptmsg *ndmsg;
1038 int err;
1039 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1040 + (opt->nd_opt_len << 3));
1041 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1042
1043 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1044 if (skb == NULL) {
1045 err = -ENOBUFS;
1046 goto errout;
1047 }
1048
1049 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1050 if (nlh == NULL) {
1051 goto nla_put_failure;
1052 }
1053
1054 ndmsg = nlmsg_data(nlh);
1055 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001056 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001057 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1058 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1059 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1060
1061 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1062
1063 NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1064 &ipv6_hdr(ra)->saddr);
1065 nlmsg_end(skb, nlh);
1066
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001067 err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL,
1068 GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001069 if (err < 0)
1070 goto errout;
1071
1072 return;
1073
1074nla_put_failure:
1075 nlmsg_free(skb);
1076 err = -EMSGSIZE;
1077errout:
Denis V. Lunev97c53ca2007-11-19 22:26:51 -08001078 rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001079}
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081static void ndisc_router_discovery(struct sk_buff *skb)
1082{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001083 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 struct neighbour *neigh = NULL;
1085 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001086 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 int lifetime;
1088 struct ndisc_options ndopts;
1089 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001090 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092 __u8 * opt = (__u8 *)(ra_msg + 1);
1093
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001094 optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001096 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 ND_PRINTK2(KERN_WARNING
1098 "ICMPv6 RA: source address is not link-local.\n");
1099 return;
1100 }
1101 if (optlen < 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001102 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 "ICMPv6 RA: packet too short\n");
1104 return;
1105 }
1106
1107 /*
1108 * set the RA_RECV flag in the interface
1109 */
1110
1111 in6_dev = in6_dev_get(skb->dev);
1112 if (in6_dev == NULL) {
1113 ND_PRINTK0(KERN_ERR
1114 "ICMPv6 RA: can't find inet6 device for %s.\n",
1115 skb->dev->name);
1116 return;
1117 }
1118 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
1119 in6_dev_put(in6_dev);
1120 return;
1121 }
1122
1123 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
1124 in6_dev_put(in6_dev);
1125 ND_PRINTK2(KERN_WARNING
1126 "ICMP6 RA: invalid ND options\n");
1127 return;
1128 }
1129
1130 if (in6_dev->if_flags & IF_RS_SENT) {
1131 /*
1132 * flag that an RA was received after an RS was sent
1133 * out on this interface.
1134 */
1135 in6_dev->if_flags |= IF_RA_RCVD;
1136 }
1137
1138 /*
1139 * Remember the managed/otherconf flags from most recently
1140 * received RA message (RFC 2462) -- yoshfuji
1141 */
1142 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1143 IF_RA_OTHERCONF)) |
1144 (ra_msg->icmph.icmp6_addrconf_managed ?
1145 IF_RA_MANAGED : 0) |
1146 (ra_msg->icmph.icmp6_addrconf_other ?
1147 IF_RA_OTHERCONF : 0);
1148
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001149 if (!in6_dev->cnf.accept_ra_defrtr)
1150 goto skip_defrtr;
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1153
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001154#ifdef CONFIG_IPV6_ROUTER_PREF
1155 pref = ra_msg->icmph.icmp6_router_pref;
1156 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001157 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001158 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001159 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1160#endif
1161
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001162 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 if (rt)
1165 neigh = rt->rt6i_nexthop;
1166
1167 if (rt && lifetime == 0) {
1168 neigh_clone(neigh);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001169 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 rt = NULL;
1171 }
1172
1173 if (rt == NULL && lifetime) {
1174 ND_PRINTK3(KERN_DEBUG
1175 "ICMPv6 RA: adding default router.\n");
1176
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001177 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (rt == NULL) {
1179 ND_PRINTK0(KERN_ERR
1180 "ICMPv6 RA: %s() failed to add default route.\n",
1181 __FUNCTION__);
1182 in6_dev_put(in6_dev);
1183 return;
1184 }
1185
1186 neigh = rt->rt6i_nexthop;
1187 if (neigh == NULL) {
1188 ND_PRINTK0(KERN_ERR
1189 "ICMPv6 RA: %s() got default router without neighbour.\n",
1190 __FUNCTION__);
1191 dst_release(&rt->u.dst);
1192 in6_dev_put(in6_dev);
1193 return;
1194 }
1195 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001196 } else if (rt) {
1197 rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 }
1199
1200 if (rt)
1201 rt->rt6i_expires = jiffies + (HZ * lifetime);
1202
1203 if (ra_msg->icmph.icmp6_hop_limit) {
1204 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1205 if (rt)
1206 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
1207 }
1208
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001209skip_defrtr:
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 /*
1212 * Update Reachable Time and Retrans Timer
1213 */
1214
1215 if (in6_dev->nd_parms) {
1216 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1217
1218 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1219 rtime = (rtime*HZ)/1000;
1220 if (rtime < HZ/10)
1221 rtime = HZ/10;
1222 in6_dev->nd_parms->retrans_time = rtime;
1223 in6_dev->tstamp = jiffies;
1224 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1225 }
1226
1227 rtime = ntohl(ra_msg->reachable_time);
1228 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1229 rtime = (rtime*HZ)/1000;
1230
1231 if (rtime < HZ/10)
1232 rtime = HZ/10;
1233
1234 if (rtime != in6_dev->nd_parms->base_reachable_time) {
1235 in6_dev->nd_parms->base_reachable_time = rtime;
1236 in6_dev->nd_parms->gc_staletime = 3 * rtime;
1237 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1238 in6_dev->tstamp = jiffies;
1239 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1240 }
1241 }
1242 }
1243
1244 /*
1245 * Process options.
1246 */
1247
1248 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001249 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 skb->dev, 1);
1251 if (neigh) {
1252 u8 *lladdr = NULL;
1253 if (ndopts.nd_opts_src_lladdr) {
1254 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1255 skb->dev);
1256 if (!lladdr) {
1257 ND_PRINTK2(KERN_WARNING
1258 "ICMPv6 RA: invalid link-layer address length\n");
1259 goto out;
1260 }
1261 }
1262 neigh_update(neigh, lladdr, NUD_STALE,
1263 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1264 NEIGH_UPDATE_F_OVERRIDE|
1265 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1266 NEIGH_UPDATE_F_ISROUTER);
1267 }
1268
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001269#ifdef CONFIG_IPV6_ROUTE_INFO
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001270 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001271 struct nd_opt_hdr *p;
1272 for (p = ndopts.nd_opts_ri;
1273 p;
1274 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001275 if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
1276 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001277 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001278 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001279 }
1280 }
1281#endif
1282
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001283 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 struct nd_opt_hdr *p;
1285 for (p = ndopts.nd_opts_pi;
1286 p;
1287 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
1288 addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3);
1289 }
1290 }
1291
1292 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001293 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 u32 mtu;
1295
Al Viroe69a4adc2006-11-14 20:56:00 -08001296 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1297 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
1300 ND_PRINTK2(KERN_WARNING
1301 "ICMPv6 RA: invalid mtu: %d\n",
1302 mtu);
1303 } else if (in6_dev->cnf.mtu6 != mtu) {
1304 in6_dev->cnf.mtu6 = mtu;
1305
1306 if (rt)
1307 rt->u.dst.metrics[RTAX_MTU-1] = mtu;
1308
1309 rt6_mtu_change(skb->dev, mtu);
1310 }
1311 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001312
Pierre Ynard31910572007-10-10 21:22:05 -07001313 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001314 struct nd_opt_hdr *p;
1315 for (p = ndopts.nd_useropts;
1316 p;
1317 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1318 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001319 }
1320 }
1321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
1323 ND_PRINTK2(KERN_WARNING
1324 "ICMPv6 RA: invalid RA options");
1325 }
1326out:
1327 if (rt)
1328 dst_release(&rt->u.dst);
1329 else if (neigh)
1330 neigh_release(neigh);
1331 in6_dev_put(in6_dev);
1332}
1333
1334static void ndisc_redirect_rcv(struct sk_buff *skb)
1335{
1336 struct inet6_dev *in6_dev;
1337 struct icmp6hdr *icmph;
1338 struct in6_addr *dest;
1339 struct in6_addr *target; /* new first hop to destination */
1340 struct neighbour *neigh;
1341 int on_link = 0;
1342 struct ndisc_options ndopts;
1343 int optlen;
1344 u8 *lladdr = NULL;
1345
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001346 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 ND_PRINTK2(KERN_WARNING
1348 "ICMPv6 Redirect: source address is not link-local.\n");
1349 return;
1350 }
1351
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001352 optlen = skb->tail - skb->transport_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1354
1355 if (optlen < 0) {
1356 ND_PRINTK2(KERN_WARNING
1357 "ICMPv6 Redirect: packet too short\n");
1358 return;
1359 }
1360
Arnaldo Carvalho de Melocc70ab22007-03-13 14:03:22 -03001361 icmph = icmp6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 target = (struct in6_addr *) (icmph + 1);
1363 dest = target + 1;
1364
1365 if (ipv6_addr_is_multicast(dest)) {
1366 ND_PRINTK2(KERN_WARNING
1367 "ICMPv6 Redirect: destination address is multicast.\n");
1368 return;
1369 }
1370
1371 if (ipv6_addr_equal(dest, target)) {
1372 on_link = 1;
Brian Haleybf0b48d2007-10-08 00:12:05 -07001373 } else if (ipv6_addr_type(target) !=
1374 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001375 ND_PRINTK2(KERN_WARNING
Brian Haleybf0b48d2007-10-08 00:12:05 -07001376 "ICMPv6 Redirect: target address is not link-local unicast.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return;
1378 }
1379
1380 in6_dev = in6_dev_get(skb->dev);
1381 if (!in6_dev)
1382 return;
1383 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
1384 in6_dev_put(in6_dev);
1385 return;
1386 }
1387
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001388 /* RFC2461 8.1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 * The IP source address of the Redirect MUST be the same as the current
1390 * first-hop router for the specified ICMP Destination Address.
1391 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
1394 ND_PRINTK2(KERN_WARNING
1395 "ICMPv6 Redirect: invalid ND options\n");
1396 in6_dev_put(in6_dev);
1397 return;
1398 }
1399 if (ndopts.nd_opts_tgt_lladdr) {
1400 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1401 skb->dev);
1402 if (!lladdr) {
1403 ND_PRINTK2(KERN_WARNING
1404 "ICMPv6 Redirect: invalid link-layer address length\n");
1405 in6_dev_put(in6_dev);
1406 return;
1407 }
1408 }
1409
1410 neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
1411 if (neigh) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001412 rt6_redirect(dest, &ipv6_hdr(skb)->daddr,
1413 &ipv6_hdr(skb)->saddr, neigh, lladdr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 on_link);
1415 neigh_release(neigh);
1416 }
1417 in6_dev_put(in6_dev);
1418}
1419
1420void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1421 struct in6_addr *target)
1422{
1423 struct sock *sk = ndisc_socket->sk;
1424 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1425 struct sk_buff *buff;
1426 struct icmp6hdr *icmph;
1427 struct in6_addr saddr_buf;
1428 struct in6_addr *addrp;
1429 struct net_device *dev;
1430 struct rt6_info *rt;
1431 struct dst_entry *dst;
1432 struct inet6_dev *idev;
1433 struct flowi fl;
1434 u8 *opt;
1435 int rd_len;
1436 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1438
1439 dev = skb->dev;
1440
Neil Horman95c385b2007-04-25 17:08:10 -07001441 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 ND_PRINTK2(KERN_WARNING
1443 "ICMPv6 Redirect: no link-local address on %s\n",
1444 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001445 return;
1446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001448 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001449 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Li Yewang29556522007-01-30 14:33:20 -08001450 ND_PRINTK2(KERN_WARNING
Brian Haleybf0b48d2007-10-08 00:12:05 -07001451 "ICMPv6 Redirect: target address is not link-local unicast.\n");
Li Yewang29556522007-01-30 14:33:20 -08001452 return;
1453 }
1454
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001455 ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr,
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -07001456 dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
1458 dst = ip6_route_output(NULL, &fl);
1459 if (dst == NULL)
1460 return;
1461
1462 err = xfrm_lookup(&dst, &fl, NULL, 0);
Patrick McHardye104411b2005-09-08 15:11:55 -07001463 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466 rt = (struct rt6_info *) dst;
1467
1468 if (rt->rt6i_flags & RTF_GATEWAY) {
1469 ND_PRINTK2(KERN_WARNING
1470 "ICMPv6 Redirect: destination is not a neighbour.\n");
1471 dst_release(dst);
1472 return;
1473 }
1474 if (!xrlim_allow(dst, 1*HZ)) {
1475 dst_release(dst);
1476 return;
1477 }
1478
1479 if (dev->addr_len) {
1480 read_lock_bh(&neigh->lock);
1481 if (neigh->nud_state & NUD_VALID) {
1482 memcpy(ha_buf, neigh->ha, dev->addr_len);
1483 read_unlock_bh(&neigh->lock);
1484 ha = ha_buf;
1485 len += ndisc_opt_addr_space(dev);
1486 } else
1487 read_unlock_bh(&neigh->lock);
1488 }
1489
1490 rd_len = min_t(unsigned int,
1491 IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
1492 rd_len &= ~0x7;
1493 len += rd_len;
1494
David S. Millerd54a81d2006-12-02 21:00:06 -08001495 buff = sock_alloc_send_skb(sk,
1496 (MAX_HEADER + sizeof(struct ipv6hdr) +
1497 len + LL_RESERVED_SPACE(dev)),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 1, &err);
1499 if (buff == NULL) {
1500 ND_PRINTK0(KERN_ERR
1501 "ICMPv6 Redirect: %s() failed to allocate an skb.\n",
1502 __FUNCTION__);
1503 dst_release(dst);
1504 return;
1505 }
1506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
1508 skb_reserve(buff, LL_RESERVED_SPACE(dev));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001509 ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 IPPROTO_ICMPV6, len);
1511
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001512 skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
Arnaldo Carvalho de Melod10ba342007-03-14 21:05:37 -03001513 skb_put(buff, len);
1514 icmph = icmp6_hdr(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 memset(icmph, 0, sizeof(struct icmp6hdr));
1517 icmph->icmp6_type = NDISC_REDIRECT;
1518
1519 /*
1520 * copy target and destination addresses
1521 */
1522
1523 addrp = (struct in6_addr *)(icmph + 1);
1524 ipv6_addr_copy(addrp, target);
1525 addrp++;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001526 ipv6_addr_copy(addrp, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 opt = (u8*) (addrp + 1);
1529
1530 /*
1531 * include target_address option
1532 */
1533
1534 if (ha)
1535 opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
1536 dev->addr_len, dev->type);
1537
1538 /*
1539 * build redirect option and copy skb over to the new packet.
1540 */
1541
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001542 memset(opt, 0, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 *(opt++) = ND_OPT_REDIRECT_HDR;
1544 *(opt++) = (rd_len >> 3);
1545 opt += 6;
1546
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001547 memcpy(opt, ipv6_hdr(skb), rd_len - 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001549 icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 len, IPPROTO_ICMPV6,
1551 csum_partial((u8 *) icmph, len, 0));
1552
1553 buff->dst = dst;
1554 idev = in6_dev_get(dst->dev);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +09001555 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001556 err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
1557 dst_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 if (!err) {
David L Stevens14878f72007-09-16 16:52:35 -07001559 ICMP6MSGOUT_INC_STATS(idev, NDISC_REDIRECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
1561 }
1562
1563 if (likely(idev != NULL))
1564 in6_dev_put(idev);
1565}
1566
1567static void pndisc_redo(struct sk_buff *skb)
1568{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001569 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 kfree_skb(skb);
1571}
1572
1573int ndisc_rcv(struct sk_buff *skb)
1574{
1575 struct nd_msg *msg;
1576
1577 if (!pskb_may_pull(skb, skb->len))
1578 return 0;
1579
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001580 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001582 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001584 if (ipv6_hdr(skb)->hop_limit != 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 ND_PRINTK2(KERN_WARNING
1586 "ICMPv6 NDISC: invalid hop-limit: %d\n",
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001587 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 return 0;
1589 }
1590
1591 if (msg->icmph.icmp6_code != 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001592 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 "ICMPv6 NDISC: invalid ICMPv6 code: %d\n",
1594 msg->icmph.icmp6_code);
1595 return 0;
1596 }
1597
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001598 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 switch (msg->icmph.icmp6_type) {
1601 case NDISC_NEIGHBOUR_SOLICITATION:
1602 ndisc_recv_ns(skb);
1603 break;
1604
1605 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1606 ndisc_recv_na(skb);
1607 break;
1608
1609 case NDISC_ROUTER_SOLICITATION:
1610 ndisc_recv_rs(skb);
1611 break;
1612
1613 case NDISC_ROUTER_ADVERTISEMENT:
1614 ndisc_router_discovery(skb);
1615 break;
1616
1617 case NDISC_REDIRECT:
1618 ndisc_redirect_rcv(skb);
1619 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 return 0;
1623}
1624
1625static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1626{
1627 struct net_device *dev = ptr;
1628
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001629 if (dev->nd_net != &init_net)
1630 return NOTIFY_DONE;
1631
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 switch (event) {
1633 case NETDEV_CHANGEADDR:
1634 neigh_changeaddr(&nd_tbl, dev);
1635 fib6_run_gc(~0UL);
1636 break;
1637 case NETDEV_DOWN:
1638 neigh_ifdown(&nd_tbl, dev);
1639 fib6_run_gc(~0UL);
1640 break;
1641 default:
1642 break;
1643 }
1644
1645 return NOTIFY_DONE;
1646}
1647
1648static struct notifier_block ndisc_netdev_notifier = {
1649 .notifier_call = ndisc_netdev_event,
1650};
1651
1652#ifdef CONFIG_SYSCTL
1653static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1654 const char *func, const char *dev_name)
1655{
1656 static char warncomm[TASK_COMM_LEN];
1657 static int warned;
1658 if (strcmp(warncomm, current->comm) && warned < 5) {
1659 strcpy(warncomm, current->comm);
1660 printk(KERN_WARNING
1661 "process `%s' is using deprecated sysctl (%s) "
1662 "net.ipv6.neigh.%s.%s; "
1663 "Use net.ipv6.neigh.%s.%s_ms "
1664 "instead.\n",
1665 warncomm, func,
1666 dev_name, ctl->procname,
1667 dev_name, ctl->procname);
1668 warned++;
1669 }
1670}
1671
1672int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos)
1673{
1674 struct net_device *dev = ctl->extra1;
1675 struct inet6_dev *idev;
1676 int ret;
1677
Eric W. Biedermand12af672007-10-18 03:05:25 -07001678 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1679 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1681
Eric W. Biedermand12af672007-10-18 03:05:25 -07001682 if (strcmp(ctl->procname, "retrans_time") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001684
1685 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 ret = proc_dointvec_jiffies(ctl, write,
1687 filp, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001688
1689 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001690 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 ret = proc_dointvec_ms_jiffies(ctl, write,
1692 filp, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001693 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Eric W. Biedermand12af672007-10-18 03:05:25 -07001697 if (ctl->data == &idev->nd_parms->base_reachable_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1699 idev->tstamp = jiffies;
1700 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1701 in6_dev_put(idev);
1702 }
1703 return ret;
1704}
1705
1706static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
1707 int nlen, void __user *oldval,
1708 size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001709 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710{
1711 struct net_device *dev = ctl->extra1;
1712 struct inet6_dev *idev;
1713 int ret;
1714
1715 if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
1716 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
1717 ndisc_warn_deprecated_sysctl(ctl, "procfs", dev ? dev->name : "default");
1718
1719 switch (ctl->ctl_name) {
1720 case NET_NEIGH_REACHABLE_TIME:
1721 ret = sysctl_jiffies(ctl, name, nlen,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001722 oldval, oldlenp, newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 break;
1724 case NET_NEIGH_RETRANS_TIME_MS:
1725 case NET_NEIGH_REACHABLE_TIME_MS:
1726 ret = sysctl_ms_jiffies(ctl, name, nlen,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001727 oldval, oldlenp, newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 break;
1729 default:
1730 ret = 0;
1731 }
1732
1733 if (newval && newlen && ret > 0 &&
1734 dev && (idev = in6_dev_get(dev)) != NULL) {
1735 if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
1736 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
1737 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1738 idev->tstamp = jiffies;
1739 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1740 in6_dev_put(idev);
1741 }
1742
1743 return ret;
1744}
1745
1746#endif
1747
1748int __init ndisc_init(struct net_proto_family *ops)
1749{
1750 struct ipv6_pinfo *np;
1751 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001752 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
1755 if (err < 0) {
1756 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001757 "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 err);
1759 ndisc_socket = NULL; /* For safety. */
1760 return err;
1761 }
1762
1763 sk = ndisc_socket->sk;
1764 np = inet6_sk(sk);
1765 sk->sk_allocation = GFP_ATOMIC;
1766 np->hop_limit = 255;
1767 /* Do not loopback ndisc messages */
1768 np->mc_loop = 0;
1769 sk->sk_prot->unhash(sk);
1770
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001771 /*
1772 * Initialize the neighbour table
1773 */
1774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 neigh_table_init(&nd_tbl);
1776
1777#ifdef CONFIG_SYSCTL
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001778 neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 "ipv6",
1780 &ndisc_ifinfo_sysctl_change,
1781 &ndisc_ifinfo_sysctl_strategy);
1782#endif
1783
1784 register_netdevice_notifier(&ndisc_netdev_notifier);
1785 return 0;
1786}
1787
1788void ndisc_cleanup(void)
1789{
Dmitry Mishin36f73d02006-11-03 16:08:19 -08001790 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791#ifdef CONFIG_SYSCTL
1792 neigh_sysctl_unregister(&nd_tbl.parms);
1793#endif
1794 neigh_table_clear(&nd_tbl);
1795 sock_release(ndisc_socket);
1796 ndisc_socket = NULL; /* For safety. */
1797}