blob: 886c5be1490674da79258c0e5d6c623eac747cf7 [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 *
18 * Lars Fenneberg : fixed MTU setting on receipt
19 * of an RA.
20 *
21 * Janos Farkas : kmalloc failure checks
22 * Alexey Kuznetsov : state machine reworked
23 * and moved to net/core.
24 * Pekka Savola : RFC2461 validation
25 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
26 */
27
28/* Set to 3 to get tracing... */
29#define ND_DEBUG 1
30
31#define ND_PRINTK(fmt, args...) do { if (net_ratelimit()) { printk(fmt, ## args); } } while(0)
32#define ND_NOPRINTK(x...) do { ; } while(0)
33#define ND_PRINTK0 ND_PRINTK
34#define ND_PRINTK1 ND_NOPRINTK
35#define ND_PRINTK2 ND_NOPRINTK
36#define ND_PRINTK3 ND_NOPRINTK
37#if ND_DEBUG >= 1
38#undef ND_PRINTK1
39#define ND_PRINTK1 ND_PRINTK
40#endif
41#if ND_DEBUG >= 2
42#undef ND_PRINTK2
43#define ND_PRINTK2 ND_PRINTK
44#endif
45#if ND_DEBUG >= 3
46#undef ND_PRINTK3
47#define ND_PRINTK3 ND_PRINTK
48#endif
49
50#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/errno.h>
52#include <linux/types.h>
53#include <linux/socket.h>
54#include <linux/sockios.h>
55#include <linux/sched.h>
56#include <linux/net.h>
57#include <linux/in6.h>
58#include <linux/route.h>
59#include <linux/init.h>
60#include <linux/rcupdate.h>
61#ifdef CONFIG_SYSCTL
62#include <linux/sysctl.h>
63#endif
64
Thomas Graf18237302006-08-04 23:04:54 -070065#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#include <linux/if_arp.h>
67#include <linux/ipv6.h>
68#include <linux/icmpv6.h>
69#include <linux/jhash.h>
70
71#include <net/sock.h>
72#include <net/snmp.h>
73
74#include <net/ipv6.h>
75#include <net/protocol.h>
76#include <net/ndisc.h>
77#include <net/ip6_route.h>
78#include <net/addrconf.h>
79#include <net/icmp.h>
80
81#include <net/flow.h>
82#include <net/ip6_checksum.h>
83#include <linux/proc_fs.h>
84
85#include <linux/netfilter.h>
86#include <linux/netfilter_ipv6.h>
87
88static struct socket *ndisc_socket;
89
90static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
91static int ndisc_constructor(struct neighbour *neigh);
92static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
93static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
94static int pndisc_constructor(struct pneigh_entry *n);
95static void pndisc_destructor(struct pneigh_entry *n);
96static void pndisc_redo(struct sk_buff *skb);
97
98static struct neigh_ops ndisc_generic_ops = {
99 .family = AF_INET6,
100 .solicit = ndisc_solicit,
101 .error_report = ndisc_error_report,
102 .output = neigh_resolve_output,
103 .connected_output = neigh_connected_output,
104 .hh_output = dev_queue_xmit,
105 .queue_xmit = dev_queue_xmit,
106};
107
108static struct neigh_ops ndisc_hh_ops = {
109 .family = AF_INET6,
110 .solicit = ndisc_solicit,
111 .error_report = ndisc_error_report,
112 .output = neigh_resolve_output,
113 .connected_output = neigh_resolve_output,
114 .hh_output = dev_queue_xmit,
115 .queue_xmit = dev_queue_xmit,
116};
117
118
119static struct neigh_ops ndisc_direct_ops = {
120 .family = AF_INET6,
121 .output = dev_queue_xmit,
122 .connected_output = dev_queue_xmit,
123 .hh_output = dev_queue_xmit,
124 .queue_xmit = dev_queue_xmit,
125};
126
127struct neigh_table nd_tbl = {
128 .family = AF_INET6,
129 .entry_size = sizeof(struct neighbour) + sizeof(struct in6_addr),
130 .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 = {
138 .tbl = &nd_tbl,
139 .base_reachable_time = 30 * HZ,
140 .retrans_time = 1 * HZ,
141 .gc_staletime = 60 * HZ,
142 .reachable_time = 30 * HZ,
143 .delay_probe_time = 5 * HZ,
144 .queue_len = 3,
145 .ucast_probes = 3,
146 .mcast_probes = 3,
147 .anycast_delay = 1 * HZ,
148 .proxy_delay = (8 * HZ) / 10,
149 .proxy_qlen = 64,
150 },
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164};
165
166#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
167#define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR]
168#define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO]
169#define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END]
170#define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
171#define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
172
173#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
174
175/*
176 * Return the padding between the option length and the start of the
177 * link addr. Currently only IP-over-InfiniBand needs this, although
178 * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
179 * also need a pad of 2.
180 */
181static int ndisc_addr_option_pad(unsigned short type)
182{
183 switch (type) {
184 case ARPHRD_INFINIBAND: return 2;
185 default: return 0;
186 }
187}
188
189static inline int ndisc_opt_addr_space(struct net_device *dev)
190{
191 return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
192}
193
194static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
195 unsigned short addr_type)
196{
197 int space = NDISC_OPT_SPACE(data_len);
198 int pad = ndisc_addr_option_pad(addr_type);
199
200 opt[0] = type;
201 opt[1] = space>>3;
202
203 memset(opt + 2, 0, pad);
204 opt += pad;
205 space -= pad;
206
207 memcpy(opt+2, data, data_len);
208 data_len += 2;
209 opt += data_len;
210 if ((space -= data_len) > 0)
211 memset(opt, 0, space);
212 return opt + space;
213}
214
215static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
216 struct nd_opt_hdr *end)
217{
218 int type;
219 if (!cur || !end || cur >= end)
220 return NULL;
221 type = cur->nd_opt_type;
222 do {
223 cur = ((void *)cur) + (cur->nd_opt_len << 3);
224 } while(cur < end && cur->nd_opt_type != type);
225 return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
226}
227
228static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
229 struct ndisc_options *ndopts)
230{
231 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
232
233 if (!nd_opt || opt_len < 0 || !ndopts)
234 return NULL;
235 memset(ndopts, 0, sizeof(*ndopts));
236 while (opt_len) {
237 int l;
238 if (opt_len < sizeof(struct nd_opt_hdr))
239 return NULL;
240 l = nd_opt->nd_opt_len << 3;
241 if (opt_len < l || l == 0)
242 return NULL;
243 switch (nd_opt->nd_opt_type) {
244 case ND_OPT_SOURCE_LL_ADDR:
245 case ND_OPT_TARGET_LL_ADDR:
246 case ND_OPT_MTU:
247 case ND_OPT_REDIRECT_HDR:
248 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
249 ND_PRINTK2(KERN_WARNING
250 "%s(): duplicated ND6 option found: type=%d\n",
251 __FUNCTION__,
252 nd_opt->nd_opt_type);
253 } else {
254 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
255 }
256 break;
257 case ND_OPT_PREFIX_INFO:
258 ndopts->nd_opts_pi_end = nd_opt;
259 if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
260 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
261 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800262#ifdef CONFIG_IPV6_ROUTE_INFO
263 case ND_OPT_ROUTE_INFO:
264 ndopts->nd_opts_ri_end = nd_opt;
265 if (!ndopts->nd_opts_ri)
266 ndopts->nd_opts_ri = nd_opt;
267 break;
268#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 default:
270 /*
271 * Unknown options must be silently ignored,
272 * to accommodate future extension to the protocol.
273 */
274 ND_PRINTK2(KERN_NOTICE
275 "%s(): ignored unsupported option; type=%d, len=%d\n",
276 __FUNCTION__,
277 nd_opt->nd_opt_type, nd_opt->nd_opt_len);
278 }
279 opt_len -= l;
280 nd_opt = ((void *)nd_opt) + l;
281 }
282 return ndopts;
283}
284
285static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
286 struct net_device *dev)
287{
288 u8 *lladdr = (u8 *)(p + 1);
289 int lladdrlen = p->nd_opt_len << 3;
290 int prepad = ndisc_addr_option_pad(dev->type);
291 if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
292 return NULL;
293 return (lladdr + prepad);
294}
295
296int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
297{
298 switch (dev->type) {
299 case ARPHRD_ETHER:
300 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
301 case ARPHRD_FDDI:
302 ipv6_eth_mc_map(addr, buf);
303 return 0;
304 case ARPHRD_IEEE802_TR:
305 ipv6_tr_mc_map(addr,buf);
306 return 0;
307 case ARPHRD_ARCNET:
308 ipv6_arcnet_mc_map(addr, buf);
309 return 0;
310 case ARPHRD_INFINIBAND:
311 ipv6_ib_mc_map(addr, buf);
312 return 0;
313 default:
314 if (dir) {
315 memcpy(buf, dev->broadcast, dev->addr_len);
316 return 0;
317 }
318 }
319 return -EINVAL;
320}
321
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900322EXPORT_SYMBOL(ndisc_mc_map);
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
325{
326 const u32 *p32 = pkey;
327 u32 addr_hash, i;
328
329 addr_hash = 0;
330 for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
331 addr_hash ^= *p32++;
332
333 return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd);
334}
335
336static int ndisc_constructor(struct neighbour *neigh)
337{
338 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
339 struct net_device *dev = neigh->dev;
340 struct inet6_dev *in6_dev;
341 struct neigh_parms *parms;
342 int is_multicast = ipv6_addr_is_multicast(addr);
343
344 rcu_read_lock();
345 in6_dev = in6_dev_get(dev);
346 if (in6_dev == NULL) {
347 rcu_read_unlock();
348 return -EINVAL;
349 }
350
351 parms = in6_dev->nd_parms;
352 __neigh_parms_put(neigh->parms);
353 neigh->parms = neigh_parms_clone(parms);
354 rcu_read_unlock();
355
356 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
357 if (dev->hard_header == NULL) {
358 neigh->nud_state = NUD_NOARP;
359 neigh->ops = &ndisc_direct_ops;
360 neigh->output = neigh->ops->queue_xmit;
361 } else {
362 if (is_multicast) {
363 neigh->nud_state = NUD_NOARP;
364 ndisc_mc_map(addr, neigh->ha, dev, 1);
365 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
366 neigh->nud_state = NUD_NOARP;
367 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
368 if (dev->flags&IFF_LOOPBACK)
369 neigh->type = RTN_LOCAL;
370 } else if (dev->flags&IFF_POINTOPOINT) {
371 neigh->nud_state = NUD_NOARP;
372 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
373 }
374 if (dev->hard_header_cache)
375 neigh->ops = &ndisc_hh_ops;
376 else
377 neigh->ops = &ndisc_generic_ops;
378 if (neigh->nud_state&NUD_VALID)
379 neigh->output = neigh->ops->connected_output;
380 else
381 neigh->output = neigh->ops->output;
382 }
383 in6_dev_put(in6_dev);
384 return 0;
385}
386
387static int pndisc_constructor(struct pneigh_entry *n)
388{
389 struct in6_addr *addr = (struct in6_addr*)&n->key;
390 struct in6_addr maddr;
391 struct net_device *dev = n->dev;
392
393 if (dev == NULL || __in6_dev_get(dev) == NULL)
394 return -EINVAL;
395 addrconf_addr_solict_mult(addr, &maddr);
396 ipv6_dev_mc_inc(dev, &maddr);
397 return 0;
398}
399
400static void pndisc_destructor(struct pneigh_entry *n)
401{
402 struct in6_addr *addr = (struct in6_addr*)&n->key;
403 struct in6_addr maddr;
404 struct net_device *dev = n->dev;
405
406 if (dev == NULL || __in6_dev_get(dev) == NULL)
407 return;
408 addrconf_addr_solict_mult(addr, &maddr);
409 ipv6_dev_mc_dec(dev, &maddr);
410}
411
412/*
413 * Send a Neighbour Advertisement
414 */
415
416static inline void ndisc_flow_init(struct flowi *fl, u8 type,
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700417 struct in6_addr *saddr, struct in6_addr *daddr,
418 int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
420 memset(fl, 0, sizeof(*fl));
421 ipv6_addr_copy(&fl->fl6_src, saddr);
422 ipv6_addr_copy(&fl->fl6_dst, daddr);
423 fl->proto = IPPROTO_ICMPV6;
424 fl->fl_icmp_type = type;
425 fl->fl_icmp_code = 0;
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700426 fl->oif = oif;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700427 security_sk_classify_flow(ndisc_socket->sk, fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
430static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
431 struct in6_addr *daddr, struct in6_addr *solicited_addr,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900432 int router, int solicited, int override, int inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433{
434 struct in6_addr tmpaddr;
435 struct inet6_ifaddr *ifp;
436 struct inet6_dev *idev;
437 struct flowi fl;
438 struct dst_entry* dst;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900439 struct sock *sk = ndisc_socket->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 struct in6_addr *src_addr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900441 struct nd_msg *msg;
442 int len;
443 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 int err;
445
446 len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
447
448 /* for anycast or proxy, solicited_addr != src_addr */
449 ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900450 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 src_addr = solicited_addr;
452 in6_ifa_put(ifp);
453 } else {
454 if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
455 return;
456 src_addr = &tmpaddr;
457 }
458
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700459 ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr,
460 dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
462 dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
463 if (!dst)
464 return;
465
466 err = xfrm_lookup(&dst, &fl, NULL, 0);
Patrick McHardye104411b2005-09-08 15:11:55 -0700467 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 if (inc_opt) {
471 if (dev->addr_len)
472 len += ndisc_opt_addr_space(dev);
473 else
474 inc_opt = 0;
475 }
476
David S. Millerd54a81d2006-12-02 21:00:06 -0800477 skb = sock_alloc_send_skb(sk,
478 (MAX_HEADER + sizeof(struct ipv6hdr) +
479 len + LL_RESERVED_SPACE(dev)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 1, &err);
481
482 if (skb == NULL) {
483 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900484 "ICMPv6 NA: %s() failed to allocate an skb.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 __FUNCTION__);
486 dst_release(dst);
487 return;
488 }
489
490 skb_reserve(skb, LL_RESERVED_SPACE(dev));
491 ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len);
492
493 msg = (struct nd_msg *)skb_put(skb, len);
494 skb->h.raw = (unsigned char*)msg;
495
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900496 msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
497 msg->icmph.icmp6_code = 0;
498 msg->icmph.icmp6_cksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900500 msg->icmph.icmp6_unused = 0;
501 msg->icmph.icmp6_router = router;
502 msg->icmph.icmp6_solicited = solicited;
503 msg->icmph.icmp6_override = override;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900505 /* Set the target address. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 ipv6_addr_copy(&msg->target, solicited_addr);
507
508 if (inc_opt)
509 ndisc_fill_addr_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr,
510 dev->addr_len, dev->type);
511
512 /* checksum */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900513 msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 IPPROTO_ICMPV6,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900515 csum_partial((__u8 *) msg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 len, 0));
517
518 skb->dst = dst;
519 idev = in6_dev_get(dst->dev);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900520 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
522 if (!err) {
523 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS);
524 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
525 }
526
527 if (likely(idev != NULL))
528 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900529}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
532 struct in6_addr *solicit,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900533 struct in6_addr *daddr, struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
535 struct flowi fl;
536 struct dst_entry* dst;
537 struct inet6_dev *idev;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900538 struct sock *sk = ndisc_socket->sk;
539 struct sk_buff *skb;
540 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 struct in6_addr addr_buf;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900542 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 int err;
544 int send_llinfo;
545
546 if (saddr == NULL) {
547 if (ipv6_get_lladdr(dev, &addr_buf))
548 return;
549 saddr = &addr_buf;
550 }
551
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700552 ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr,
553 dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
556 if (!dst)
557 return;
558
559 err = xfrm_lookup(&dst, &fl, NULL, 0);
Patrick McHardye104411b2005-09-08 15:11:55 -0700560 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
564 send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
565 if (send_llinfo)
566 len += ndisc_opt_addr_space(dev);
567
David S. Millerd54a81d2006-12-02 21:00:06 -0800568 skb = sock_alloc_send_skb(sk,
569 (MAX_HEADER + sizeof(struct ipv6hdr) +
570 len + LL_RESERVED_SPACE(dev)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 1, &err);
572 if (skb == NULL) {
573 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900574 "ICMPv6 NA: %s() failed to allocate an skb.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 __FUNCTION__);
576 dst_release(dst);
577 return;
578 }
579
580 skb_reserve(skb, LL_RESERVED_SPACE(dev));
581 ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
582
583 msg = (struct nd_msg *)skb_put(skb, len);
584 skb->h.raw = (unsigned char*)msg;
585 msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
586 msg->icmph.icmp6_code = 0;
587 msg->icmph.icmp6_cksum = 0;
588 msg->icmph.icmp6_unused = 0;
589
590 /* Set the target address. */
591 ipv6_addr_copy(&msg->target, solicit);
592
593 if (send_llinfo)
594 ndisc_fill_addr_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
595 dev->addr_len, dev->type);
596
597 /* checksum */
598 msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900599 daddr, len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 IPPROTO_ICMPV6,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900601 csum_partial((__u8 *) msg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 len, 0));
603 /* send it! */
604 skb->dst = dst;
605 idev = in6_dev_get(dst->dev);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900606 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
608 if (!err) {
609 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);
610 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
611 }
612
613 if (likely(idev != NULL))
614 in6_dev_put(idev);
615}
616
617void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
618 struct in6_addr *daddr)
619{
620 struct flowi fl;
621 struct dst_entry* dst;
622 struct inet6_dev *idev;
623 struct sock *sk = ndisc_socket->sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900624 struct sk_buff *skb;
625 struct icmp6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 __u8 * opt;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900627 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 int err;
629
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -0700630 ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr,
631 dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output);
634 if (!dst)
635 return;
636
637 err = xfrm_lookup(&dst, &fl, NULL, 0);
Patrick McHardye104411b2005-09-08 15:11:55 -0700638 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 len = sizeof(struct icmp6hdr);
642 if (dev->addr_len)
643 len += ndisc_opt_addr_space(dev);
644
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900645 skb = sock_alloc_send_skb(sk,
David S. Millerd54a81d2006-12-02 21:00:06 -0800646 (MAX_HEADER + sizeof(struct ipv6hdr) +
647 len + LL_RESERVED_SPACE(dev)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 1, &err);
649 if (skb == NULL) {
650 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900651 "ICMPv6 RS: %s() failed to allocate an skb.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 __FUNCTION__);
653 dst_release(dst);
654 return;
655 }
656
657 skb_reserve(skb, LL_RESERVED_SPACE(dev));
658 ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
659
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900660 hdr = (struct icmp6hdr *)skb_put(skb, len);
661 skb->h.raw = (unsigned char*)hdr;
662 hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
663 hdr->icmp6_code = 0;
664 hdr->icmp6_cksum = 0;
665 hdr->icmp6_unused = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 opt = (u8*) (hdr + 1);
668
669 if (dev->addr_len)
670 ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
671 dev->addr_len, dev->type);
672
673 /* checksum */
674 hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
675 IPPROTO_ICMPV6,
676 csum_partial((__u8 *) hdr, len, 0));
677
678 /* send it! */
679 skb->dst = dst;
680 idev = in6_dev_get(dst->dev);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900681 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
683 if (!err) {
684 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS);
685 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
686 }
687
688 if (likely(idev != NULL))
689 in6_dev_put(idev);
690}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
694{
695 /*
696 * "The sender MUST return an ICMP
697 * destination unreachable"
698 */
699 dst_link_failure(skb);
700 kfree_skb(skb);
701}
702
703/* Called with locked neigh: either read or both */
704
705static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
706{
707 struct in6_addr *saddr = NULL;
708 struct in6_addr mcaddr;
709 struct net_device *dev = neigh->dev;
710 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
711 int probes = atomic_read(&neigh->probes);
712
713 if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1))
714 saddr = &skb->nh.ipv6h->saddr;
715
716 if ((probes -= neigh->parms->ucast_probes) < 0) {
717 if (!(neigh->nud_state & NUD_VALID)) {
718 ND_PRINTK1(KERN_DEBUG
719 "%s(): trying to ucast probe in NUD_INVALID: "
Joe Perches46b86a22006-01-13 14:29:07 -0800720 NIP6_FMT "\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 __FUNCTION__,
722 NIP6(*target));
723 }
724 ndisc_send_ns(dev, neigh, target, target, saddr);
725 } else if ((probes -= neigh->parms->app_probes) < 0) {
726#ifdef CONFIG_ARPD
727 neigh_app_ns(neigh);
728#endif
729 } else {
730 addrconf_addr_solict_mult(target, &mcaddr);
731 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
732 }
733}
734
735static void ndisc_recv_ns(struct sk_buff *skb)
736{
737 struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
738 struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
739 struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
740 u8 *lladdr = NULL;
741 u32 ndoptlen = skb->tail - msg->opt;
742 struct ndisc_options ndopts;
743 struct net_device *dev = skb->dev;
744 struct inet6_ifaddr *ifp;
745 struct inet6_dev *idev = NULL;
746 struct neighbour *neigh;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700747 struct pneigh_entry *pneigh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 int dad = ipv6_addr_any(saddr);
749 int inc;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700750 int is_router;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752 if (ipv6_addr_is_multicast(&msg->target)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900753 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 "ICMPv6 NS: multicast target address");
755 return;
756 }
757
758 /*
759 * RFC2461 7.1.1:
760 * DAD has to be destined for solicited node multicast address.
761 */
762 if (dad &&
763 !(daddr->s6_addr32[0] == htonl(0xff020000) &&
764 daddr->s6_addr32[1] == htonl(0x00000000) &&
765 daddr->s6_addr32[2] == htonl(0x00000001) &&
766 daddr->s6_addr [12] == 0xff )) {
767 ND_PRINTK2(KERN_WARNING
768 "ICMPv6 NS: bad DAD packet (wrong destination)\n");
769 return;
770 }
771
772 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900773 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 "ICMPv6 NS: invalid ND options\n");
775 return;
776 }
777
778 if (ndopts.nd_opts_src_lladdr) {
779 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
780 if (!lladdr) {
781 ND_PRINTK2(KERN_WARNING
782 "ICMPv6 NS: invalid link-layer address length\n");
783 return;
784 }
785
786 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900787 * If the IP source address is the unspecified address,
788 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 * in the message.
790 */
791 if (dad) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900792 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 "ICMPv6 NS: bad DAD packet (link-layer address option)\n");
794 return;
795 }
796 }
797
798 inc = ipv6_addr_is_multicast(daddr);
799
800 if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
801 if (ifp->flags & IFA_F_TENTATIVE) {
802 /* Address is tentative. If the source
803 is unspecified address, it is someone
804 does DAD, otherwise we ignore solicitations
805 until DAD timer expires.
806 */
807 if (!dad)
808 goto out;
809 if (dev->type == ARPHRD_IEEE802_TR) {
810 unsigned char *sadr = skb->mac.raw;
811 if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
812 sadr[9] == dev->dev_addr[1] &&
813 sadr[10] == dev->dev_addr[2] &&
814 sadr[11] == dev->dev_addr[3] &&
815 sadr[12] == dev->dev_addr[4] &&
816 sadr[13] == dev->dev_addr[5]) {
817 /* looped-back to us */
818 goto out;
819 }
820 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900821 addrconf_dad_failure(ifp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return;
823 }
824
825 idev = ifp->idev;
826 } else {
827 idev = in6_dev_get(dev);
828 if (!idev) {
829 /* XXX: count this drop? */
830 return;
831 }
832
833 if (ipv6_chk_acast_addr(dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900834 (idev->cnf.forwarding &&
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700835 (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700836 (pneigh = pneigh_lookup(&nd_tbl,
837 &msg->target, dev, 0)) != NULL)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700838 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 skb->pkt_type != PACKET_HOST &&
840 inc != 0 &&
841 idev->nd_parms->proxy_delay != 0) {
842 /*
843 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900844 * sender should delay its response
845 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 * MAX_ANYCAST_DELAY_TIME seconds.
847 * (RFC2461) -- yoshfuji
848 */
849 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
850 if (n)
851 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
852 goto out;
853 }
854 } else
855 goto out;
856 }
857
YOSHIFUJI Hideakifc26d0a2006-09-22 14:44:53 -0700858 is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding);
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700859
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 if (dad) {
861 struct in6_addr maddr;
862
863 ipv6_addr_all_nodes(&maddr);
864 ndisc_send_na(dev, NULL, &maddr, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700865 is_router, 0, (ifp != NULL), 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 goto out;
867 }
868
869 if (inc)
870 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
871 else
872 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
873
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900874 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 * update / create cache entry
876 * for the source address
877 */
878 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
879 !inc || lladdr || !dev->addr_len);
880 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900881 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 NEIGH_UPDATE_F_WEAK_OVERRIDE|
883 NEIGH_UPDATE_F_OVERRIDE);
884 if (neigh || !dev->hard_header) {
885 ndisc_send_na(dev, neigh, saddr, &msg->target,
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700886 is_router,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 1, (ifp != NULL && inc), inc);
888 if (neigh)
889 neigh_release(neigh);
890 }
891
892out:
893 if (ifp)
894 in6_ifa_put(ifp);
895 else
896 in6_dev_put(idev);
897
898 return;
899}
900
901static void ndisc_recv_na(struct sk_buff *skb)
902{
903 struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
904 struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
905 struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
906 u8 *lladdr = NULL;
907 u32 ndoptlen = skb->tail - msg->opt;
908 struct ndisc_options ndopts;
909 struct net_device *dev = skb->dev;
910 struct inet6_ifaddr *ifp;
911 struct neighbour *neigh;
912
913 if (skb->len < sizeof(struct nd_msg)) {
914 ND_PRINTK2(KERN_WARNING
915 "ICMPv6 NA: packet too short\n");
916 return;
917 }
918
919 if (ipv6_addr_is_multicast(&msg->target)) {
920 ND_PRINTK2(KERN_WARNING
921 "ICMPv6 NA: target address is multicast.\n");
922 return;
923 }
924
925 if (ipv6_addr_is_multicast(daddr) &&
926 msg->icmph.icmp6_solicited) {
927 ND_PRINTK2(KERN_WARNING
928 "ICMPv6 NA: solicited NA is multicasted.\n");
929 return;
930 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
933 ND_PRINTK2(KERN_WARNING
934 "ICMPv6 NS: invalid ND option\n");
935 return;
936 }
937 if (ndopts.nd_opts_tgt_lladdr) {
938 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
939 if (!lladdr) {
940 ND_PRINTK2(KERN_WARNING
941 "ICMPv6 NA: invalid link-layer address length\n");
942 return;
943 }
944 }
945 if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1))) {
946 if (ifp->flags & IFA_F_TENTATIVE) {
947 addrconf_dad_failure(ifp);
948 return;
949 }
950 /* What should we make now? The advertisement
951 is invalid, but ndisc specs say nothing
952 about it. It could be misconfiguration, or
953 an smart proxy agent tries to help us :-)
954 */
955 ND_PRINTK1(KERN_WARNING
956 "ICMPv6 NA: someone advertises our address on %s!\n",
957 ifp->idev->dev->name);
958 in6_ifa_put(ifp);
959 return;
960 }
961 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
962
963 if (neigh) {
964 u8 old_flags = neigh->flags;
965
966 if (neigh->nud_state & NUD_FAILED)
967 goto out;
968
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700969 /*
970 * Don't update the neighbor cache entry on a proxy NA from
971 * ourselves because either the proxied node is off link or it
972 * has already sent a NA to us.
973 */
974 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700975 ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
976 pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
977 /* XXX: idev->cnf.prixy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700978 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700979 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 neigh_update(neigh, lladdr,
982 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
983 NEIGH_UPDATE_F_WEAK_OVERRIDE|
984 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
985 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
986 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
987
988 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
989 /*
990 * Change: router to host
991 */
992 struct rt6_info *rt;
993 rt = rt6_get_dflt_router(saddr, dev);
994 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700995 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997
998out:
999 neigh_release(neigh);
1000 }
1001}
1002
1003static void ndisc_recv_rs(struct sk_buff *skb)
1004{
1005 struct rs_msg *rs_msg = (struct rs_msg *) skb->h.raw;
1006 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
1007 struct neighbour *neigh;
1008 struct inet6_dev *idev;
1009 struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
1010 struct ndisc_options ndopts;
1011 u8 *lladdr = NULL;
1012
1013 if (skb->len < sizeof(*rs_msg))
1014 return;
1015
1016 idev = in6_dev_get(skb->dev);
1017 if (!idev) {
1018 if (net_ratelimit())
1019 ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
1020 return;
1021 }
1022
1023 /* Don't accept RS if we're not in router mode */
1024 if (!idev->cnf.forwarding)
1025 goto out;
1026
1027 /*
1028 * Don't update NCE if src = ::;
1029 * this implies that the source node has no ip address assigned yet.
1030 */
1031 if (ipv6_addr_any(saddr))
1032 goto out;
1033
1034 /* Parse ND options */
1035 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
1036 if (net_ratelimit())
1037 ND_PRINTK2("ICMP6 NS: invalid ND option, ignored\n");
1038 goto out;
1039 }
1040
1041 if (ndopts.nd_opts_src_lladdr) {
1042 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1043 skb->dev);
1044 if (!lladdr)
1045 goto out;
1046 }
1047
1048 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
1049 if (neigh) {
1050 neigh_update(neigh, lladdr, NUD_STALE,
1051 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1052 NEIGH_UPDATE_F_OVERRIDE|
1053 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1054 neigh_release(neigh);
1055 }
1056out:
1057 in6_dev_put(idev);
1058}
1059
1060static void ndisc_router_discovery(struct sk_buff *skb)
1061{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001062 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 struct neighbour *neigh = NULL;
1064 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001065 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 int lifetime;
1067 struct ndisc_options ndopts;
1068 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001069 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 __u8 * opt = (__u8 *)(ra_msg + 1);
1072
1073 optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);
1074
1075 if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
1076 ND_PRINTK2(KERN_WARNING
1077 "ICMPv6 RA: source address is not link-local.\n");
1078 return;
1079 }
1080 if (optlen < 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001081 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 "ICMPv6 RA: packet too short\n");
1083 return;
1084 }
1085
1086 /*
1087 * set the RA_RECV flag in the interface
1088 */
1089
1090 in6_dev = in6_dev_get(skb->dev);
1091 if (in6_dev == NULL) {
1092 ND_PRINTK0(KERN_ERR
1093 "ICMPv6 RA: can't find inet6 device for %s.\n",
1094 skb->dev->name);
1095 return;
1096 }
1097 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
1098 in6_dev_put(in6_dev);
1099 return;
1100 }
1101
1102 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
1103 in6_dev_put(in6_dev);
1104 ND_PRINTK2(KERN_WARNING
1105 "ICMP6 RA: invalid ND options\n");
1106 return;
1107 }
1108
1109 if (in6_dev->if_flags & IF_RS_SENT) {
1110 /*
1111 * flag that an RA was received after an RS was sent
1112 * out on this interface.
1113 */
1114 in6_dev->if_flags |= IF_RA_RCVD;
1115 }
1116
1117 /*
1118 * Remember the managed/otherconf flags from most recently
1119 * received RA message (RFC 2462) -- yoshfuji
1120 */
1121 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1122 IF_RA_OTHERCONF)) |
1123 (ra_msg->icmph.icmp6_addrconf_managed ?
1124 IF_RA_MANAGED : 0) |
1125 (ra_msg->icmph.icmp6_addrconf_other ?
1126 IF_RA_OTHERCONF : 0);
1127
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001128 if (!in6_dev->cnf.accept_ra_defrtr)
1129 goto skip_defrtr;
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1132
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001133#ifdef CONFIG_IPV6_ROUTER_PREF
1134 pref = ra_msg->icmph.icmp6_router_pref;
1135 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001136 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
1137 in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001138 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1139#endif
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
1142
1143 if (rt)
1144 neigh = rt->rt6i_nexthop;
1145
1146 if (rt && lifetime == 0) {
1147 neigh_clone(neigh);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001148 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 rt = NULL;
1150 }
1151
1152 if (rt == NULL && lifetime) {
1153 ND_PRINTK3(KERN_DEBUG
1154 "ICMPv6 RA: adding default router.\n");
1155
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001156 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 if (rt == NULL) {
1158 ND_PRINTK0(KERN_ERR
1159 "ICMPv6 RA: %s() failed to add default route.\n",
1160 __FUNCTION__);
1161 in6_dev_put(in6_dev);
1162 return;
1163 }
1164
1165 neigh = rt->rt6i_nexthop;
1166 if (neigh == NULL) {
1167 ND_PRINTK0(KERN_ERR
1168 "ICMPv6 RA: %s() got default router without neighbour.\n",
1169 __FUNCTION__);
1170 dst_release(&rt->u.dst);
1171 in6_dev_put(in6_dev);
1172 return;
1173 }
1174 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001175 } else if (rt) {
1176 rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
1178
1179 if (rt)
1180 rt->rt6i_expires = jiffies + (HZ * lifetime);
1181
1182 if (ra_msg->icmph.icmp6_hop_limit) {
1183 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1184 if (rt)
1185 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
1186 }
1187
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001188skip_defrtr:
1189
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 /*
1191 * Update Reachable Time and Retrans Timer
1192 */
1193
1194 if (in6_dev->nd_parms) {
1195 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1196
1197 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1198 rtime = (rtime*HZ)/1000;
1199 if (rtime < HZ/10)
1200 rtime = HZ/10;
1201 in6_dev->nd_parms->retrans_time = rtime;
1202 in6_dev->tstamp = jiffies;
1203 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1204 }
1205
1206 rtime = ntohl(ra_msg->reachable_time);
1207 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1208 rtime = (rtime*HZ)/1000;
1209
1210 if (rtime < HZ/10)
1211 rtime = HZ/10;
1212
1213 if (rtime != in6_dev->nd_parms->base_reachable_time) {
1214 in6_dev->nd_parms->base_reachable_time = rtime;
1215 in6_dev->nd_parms->gc_staletime = 3 * rtime;
1216 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1217 in6_dev->tstamp = jiffies;
1218 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1219 }
1220 }
1221 }
1222
1223 /*
1224 * Process options.
1225 */
1226
1227 if (!neigh)
1228 neigh = __neigh_lookup(&nd_tbl, &skb->nh.ipv6h->saddr,
1229 skb->dev, 1);
1230 if (neigh) {
1231 u8 *lladdr = NULL;
1232 if (ndopts.nd_opts_src_lladdr) {
1233 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1234 skb->dev);
1235 if (!lladdr) {
1236 ND_PRINTK2(KERN_WARNING
1237 "ICMPv6 RA: invalid link-layer address length\n");
1238 goto out;
1239 }
1240 }
1241 neigh_update(neigh, lladdr, NUD_STALE,
1242 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1243 NEIGH_UPDATE_F_OVERRIDE|
1244 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1245 NEIGH_UPDATE_F_ISROUTER);
1246 }
1247
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001248#ifdef CONFIG_IPV6_ROUTE_INFO
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001249 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001250 struct nd_opt_hdr *p;
1251 for (p = ndopts.nd_opts_ri;
1252 p;
1253 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001254 if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
1255 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001256 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
1257 &skb->nh.ipv6h->saddr);
1258 }
1259 }
1260#endif
1261
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001262 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 struct nd_opt_hdr *p;
1264 for (p = ndopts.nd_opts_pi;
1265 p;
1266 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
1267 addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3);
1268 }
1269 }
1270
1271 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001272 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 u32 mtu;
1274
Al Viroe69a4adc2006-11-14 20:56:00 -08001275 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1276 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
1279 ND_PRINTK2(KERN_WARNING
1280 "ICMPv6 RA: invalid mtu: %d\n",
1281 mtu);
1282 } else if (in6_dev->cnf.mtu6 != mtu) {
1283 in6_dev->cnf.mtu6 = mtu;
1284
1285 if (rt)
1286 rt->u.dst.metrics[RTAX_MTU-1] = mtu;
1287
1288 rt6_mtu_change(skb->dev, mtu);
1289 }
1290 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
1293 ND_PRINTK2(KERN_WARNING
1294 "ICMPv6 RA: invalid RA options");
1295 }
1296out:
1297 if (rt)
1298 dst_release(&rt->u.dst);
1299 else if (neigh)
1300 neigh_release(neigh);
1301 in6_dev_put(in6_dev);
1302}
1303
1304static void ndisc_redirect_rcv(struct sk_buff *skb)
1305{
1306 struct inet6_dev *in6_dev;
1307 struct icmp6hdr *icmph;
1308 struct in6_addr *dest;
1309 struct in6_addr *target; /* new first hop to destination */
1310 struct neighbour *neigh;
1311 int on_link = 0;
1312 struct ndisc_options ndopts;
1313 int optlen;
1314 u8 *lladdr = NULL;
1315
1316 if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
1317 ND_PRINTK2(KERN_WARNING
1318 "ICMPv6 Redirect: source address is not link-local.\n");
1319 return;
1320 }
1321
1322 optlen = skb->tail - skb->h.raw;
1323 optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1324
1325 if (optlen < 0) {
1326 ND_PRINTK2(KERN_WARNING
1327 "ICMPv6 Redirect: packet too short\n");
1328 return;
1329 }
1330
1331 icmph = (struct icmp6hdr *) skb->h.raw;
1332 target = (struct in6_addr *) (icmph + 1);
1333 dest = target + 1;
1334
1335 if (ipv6_addr_is_multicast(dest)) {
1336 ND_PRINTK2(KERN_WARNING
1337 "ICMPv6 Redirect: destination address is multicast.\n");
1338 return;
1339 }
1340
1341 if (ipv6_addr_equal(dest, target)) {
1342 on_link = 1;
1343 } else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001344 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 "ICMPv6 Redirect: target address is not link-local.\n");
1346 return;
1347 }
1348
1349 in6_dev = in6_dev_get(skb->dev);
1350 if (!in6_dev)
1351 return;
1352 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
1353 in6_dev_put(in6_dev);
1354 return;
1355 }
1356
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001357 /* RFC2461 8.1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 * The IP source address of the Redirect MUST be the same as the current
1359 * first-hop router for the specified ICMP Destination Address.
1360 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
1363 ND_PRINTK2(KERN_WARNING
1364 "ICMPv6 Redirect: invalid ND options\n");
1365 in6_dev_put(in6_dev);
1366 return;
1367 }
1368 if (ndopts.nd_opts_tgt_lladdr) {
1369 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1370 skb->dev);
1371 if (!lladdr) {
1372 ND_PRINTK2(KERN_WARNING
1373 "ICMPv6 Redirect: invalid link-layer address length\n");
1374 in6_dev_put(in6_dev);
1375 return;
1376 }
1377 }
1378
1379 neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
1380 if (neigh) {
YOSHIFUJI Hideaki5e032e32006-08-23 17:12:24 -07001381 rt6_redirect(dest, &skb->nh.ipv6h->daddr,
1382 &skb->nh.ipv6h->saddr, neigh, lladdr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 on_link);
1384 neigh_release(neigh);
1385 }
1386 in6_dev_put(in6_dev);
1387}
1388
1389void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1390 struct in6_addr *target)
1391{
1392 struct sock *sk = ndisc_socket->sk;
1393 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1394 struct sk_buff *buff;
1395 struct icmp6hdr *icmph;
1396 struct in6_addr saddr_buf;
1397 struct in6_addr *addrp;
1398 struct net_device *dev;
1399 struct rt6_info *rt;
1400 struct dst_entry *dst;
1401 struct inet6_dev *idev;
1402 struct flowi fl;
1403 u8 *opt;
1404 int rd_len;
1405 int err;
1406 int hlen;
1407 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1408
1409 dev = skb->dev;
1410
1411 if (ipv6_get_lladdr(dev, &saddr_buf)) {
1412 ND_PRINTK2(KERN_WARNING
1413 "ICMPv6 Redirect: no link-local address on %s\n",
1414 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001415 return;
1416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Li Yewang29556522007-01-30 14:33:20 -08001418 if (!ipv6_addr_equal(&skb->nh.ipv6h->daddr, target) &&
1419 !(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
1420 ND_PRINTK2(KERN_WARNING
1421 "ICMPv6 Redirect: target address is not link-local.\n");
1422 return;
1423 }
1424
YOSHIFUJI Hideakiaf184762006-08-23 17:18:57 -07001425 ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr,
1426 dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 dst = ip6_route_output(NULL, &fl);
1429 if (dst == NULL)
1430 return;
1431
1432 err = xfrm_lookup(&dst, &fl, NULL, 0);
Patrick McHardye104411b2005-09-08 15:11:55 -07001433 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
1436 rt = (struct rt6_info *) dst;
1437
1438 if (rt->rt6i_flags & RTF_GATEWAY) {
1439 ND_PRINTK2(KERN_WARNING
1440 "ICMPv6 Redirect: destination is not a neighbour.\n");
1441 dst_release(dst);
1442 return;
1443 }
1444 if (!xrlim_allow(dst, 1*HZ)) {
1445 dst_release(dst);
1446 return;
1447 }
1448
1449 if (dev->addr_len) {
1450 read_lock_bh(&neigh->lock);
1451 if (neigh->nud_state & NUD_VALID) {
1452 memcpy(ha_buf, neigh->ha, dev->addr_len);
1453 read_unlock_bh(&neigh->lock);
1454 ha = ha_buf;
1455 len += ndisc_opt_addr_space(dev);
1456 } else
1457 read_unlock_bh(&neigh->lock);
1458 }
1459
1460 rd_len = min_t(unsigned int,
1461 IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
1462 rd_len &= ~0x7;
1463 len += rd_len;
1464
David S. Millerd54a81d2006-12-02 21:00:06 -08001465 buff = sock_alloc_send_skb(sk,
1466 (MAX_HEADER + sizeof(struct ipv6hdr) +
1467 len + LL_RESERVED_SPACE(dev)),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 1, &err);
1469 if (buff == NULL) {
1470 ND_PRINTK0(KERN_ERR
1471 "ICMPv6 Redirect: %s() failed to allocate an skb.\n",
1472 __FUNCTION__);
1473 dst_release(dst);
1474 return;
1475 }
1476
1477 hlen = 0;
1478
1479 skb_reserve(buff, LL_RESERVED_SPACE(dev));
1480 ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr,
1481 IPPROTO_ICMPV6, len);
1482
1483 icmph = (struct icmp6hdr *)skb_put(buff, len);
1484 buff->h.raw = (unsigned char*)icmph;
1485
1486 memset(icmph, 0, sizeof(struct icmp6hdr));
1487 icmph->icmp6_type = NDISC_REDIRECT;
1488
1489 /*
1490 * copy target and destination addresses
1491 */
1492
1493 addrp = (struct in6_addr *)(icmph + 1);
1494 ipv6_addr_copy(addrp, target);
1495 addrp++;
1496 ipv6_addr_copy(addrp, &skb->nh.ipv6h->daddr);
1497
1498 opt = (u8*) (addrp + 1);
1499
1500 /*
1501 * include target_address option
1502 */
1503
1504 if (ha)
1505 opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
1506 dev->addr_len, dev->type);
1507
1508 /*
1509 * build redirect option and copy skb over to the new packet.
1510 */
1511
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001512 memset(opt, 0, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 *(opt++) = ND_OPT_REDIRECT_HDR;
1514 *(opt++) = (rd_len >> 3);
1515 opt += 6;
1516
1517 memcpy(opt, skb->nh.ipv6h, rd_len - 8);
1518
1519 icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &skb->nh.ipv6h->saddr,
1520 len, IPPROTO_ICMPV6,
1521 csum_partial((u8 *) icmph, len, 0));
1522
1523 buff->dst = dst;
1524 idev = in6_dev_get(dst->dev);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +09001525 IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output);
1527 if (!err) {
1528 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTREDIRECTS);
1529 ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
1530 }
1531
1532 if (likely(idev != NULL))
1533 in6_dev_put(idev);
1534}
1535
1536static void pndisc_redo(struct sk_buff *skb)
1537{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001538 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 kfree_skb(skb);
1540}
1541
1542int ndisc_rcv(struct sk_buff *skb)
1543{
1544 struct nd_msg *msg;
1545
1546 if (!pskb_may_pull(skb, skb->len))
1547 return 0;
1548
1549 msg = (struct nd_msg *) skb->h.raw;
1550
1551 __skb_push(skb, skb->data-skb->h.raw);
1552
1553 if (skb->nh.ipv6h->hop_limit != 255) {
1554 ND_PRINTK2(KERN_WARNING
1555 "ICMPv6 NDISC: invalid hop-limit: %d\n",
1556 skb->nh.ipv6h->hop_limit);
1557 return 0;
1558 }
1559
1560 if (msg->icmph.icmp6_code != 0) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001561 ND_PRINTK2(KERN_WARNING
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 "ICMPv6 NDISC: invalid ICMPv6 code: %d\n",
1563 msg->icmph.icmp6_code);
1564 return 0;
1565 }
1566
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001567 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 switch (msg->icmph.icmp6_type) {
1570 case NDISC_NEIGHBOUR_SOLICITATION:
1571 ndisc_recv_ns(skb);
1572 break;
1573
1574 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1575 ndisc_recv_na(skb);
1576 break;
1577
1578 case NDISC_ROUTER_SOLICITATION:
1579 ndisc_recv_rs(skb);
1580 break;
1581
1582 case NDISC_ROUTER_ADVERTISEMENT:
1583 ndisc_router_discovery(skb);
1584 break;
1585
1586 case NDISC_REDIRECT:
1587 ndisc_redirect_rcv(skb);
1588 break;
1589 };
1590
1591 return 0;
1592}
1593
1594static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1595{
1596 struct net_device *dev = ptr;
1597
1598 switch (event) {
1599 case NETDEV_CHANGEADDR:
1600 neigh_changeaddr(&nd_tbl, dev);
1601 fib6_run_gc(~0UL);
1602 break;
1603 case NETDEV_DOWN:
1604 neigh_ifdown(&nd_tbl, dev);
1605 fib6_run_gc(~0UL);
1606 break;
1607 default:
1608 break;
1609 }
1610
1611 return NOTIFY_DONE;
1612}
1613
1614static struct notifier_block ndisc_netdev_notifier = {
1615 .notifier_call = ndisc_netdev_event,
1616};
1617
1618#ifdef CONFIG_SYSCTL
1619static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1620 const char *func, const char *dev_name)
1621{
1622 static char warncomm[TASK_COMM_LEN];
1623 static int warned;
1624 if (strcmp(warncomm, current->comm) && warned < 5) {
1625 strcpy(warncomm, current->comm);
1626 printk(KERN_WARNING
1627 "process `%s' is using deprecated sysctl (%s) "
1628 "net.ipv6.neigh.%s.%s; "
1629 "Use net.ipv6.neigh.%s.%s_ms "
1630 "instead.\n",
1631 warncomm, func,
1632 dev_name, ctl->procname,
1633 dev_name, ctl->procname);
1634 warned++;
1635 }
1636}
1637
1638int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos)
1639{
1640 struct net_device *dev = ctl->extra1;
1641 struct inet6_dev *idev;
1642 int ret;
1643
1644 if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
1645 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
1646 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1647
1648 switch (ctl->ctl_name) {
1649 case NET_NEIGH_RETRANS_TIME:
1650 ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1651 break;
1652 case NET_NEIGH_REACHABLE_TIME:
1653 ret = proc_dointvec_jiffies(ctl, write,
1654 filp, buffer, lenp, ppos);
1655 break;
1656 case NET_NEIGH_RETRANS_TIME_MS:
1657 case NET_NEIGH_REACHABLE_TIME_MS:
1658 ret = proc_dointvec_ms_jiffies(ctl, write,
1659 filp, buffer, lenp, ppos);
1660 break;
1661 default:
1662 ret = -1;
1663 }
1664
1665 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
1666 if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
1667 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
1668 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1669 idev->tstamp = jiffies;
1670 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1671 in6_dev_put(idev);
1672 }
1673 return ret;
1674}
1675
1676static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
1677 int nlen, void __user *oldval,
1678 size_t __user *oldlenp,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001679 void __user *newval, size_t newlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 struct net_device *dev = ctl->extra1;
1682 struct inet6_dev *idev;
1683 int ret;
1684
1685 if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME ||
1686 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME)
1687 ndisc_warn_deprecated_sysctl(ctl, "procfs", dev ? dev->name : "default");
1688
1689 switch (ctl->ctl_name) {
1690 case NET_NEIGH_REACHABLE_TIME:
1691 ret = sysctl_jiffies(ctl, name, nlen,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001692 oldval, oldlenp, newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 break;
1694 case NET_NEIGH_RETRANS_TIME_MS:
1695 case NET_NEIGH_REACHABLE_TIME_MS:
1696 ret = sysctl_ms_jiffies(ctl, name, nlen,
Alexey Dobriyan1f29bcd2006-12-10 02:19:10 -08001697 oldval, oldlenp, newval, newlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 break;
1699 default:
1700 ret = 0;
1701 }
1702
1703 if (newval && newlen && ret > 0 &&
1704 dev && (idev = in6_dev_get(dev)) != NULL) {
1705 if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME ||
1706 ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS)
1707 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1708 idev->tstamp = jiffies;
1709 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1710 in6_dev_put(idev);
1711 }
1712
1713 return ret;
1714}
1715
1716#endif
1717
1718int __init ndisc_init(struct net_proto_family *ops)
1719{
1720 struct ipv6_pinfo *np;
1721 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001722 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
1725 if (err < 0) {
1726 ND_PRINTK0(KERN_ERR
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001727 "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 err);
1729 ndisc_socket = NULL; /* For safety. */
1730 return err;
1731 }
1732
1733 sk = ndisc_socket->sk;
1734 np = inet6_sk(sk);
1735 sk->sk_allocation = GFP_ATOMIC;
1736 np->hop_limit = 255;
1737 /* Do not loopback ndisc messages */
1738 np->mc_loop = 0;
1739 sk->sk_prot->unhash(sk);
1740
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001741 /*
1742 * Initialize the neighbour table
1743 */
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 neigh_table_init(&nd_tbl);
1746
1747#ifdef CONFIG_SYSCTL
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001748 neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 "ipv6",
1750 &ndisc_ifinfo_sysctl_change,
1751 &ndisc_ifinfo_sysctl_strategy);
1752#endif
1753
1754 register_netdevice_notifier(&ndisc_netdev_notifier);
1755 return 0;
1756}
1757
1758void ndisc_cleanup(void)
1759{
Dmitry Mishin36f73d02006-11-03 16:08:19 -08001760 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761#ifdef CONFIG_SYSCTL
1762 neigh_sysctl_unregister(&nd_tbl.parms);
1763#endif
1764 neigh_table_clear(&nd_tbl);
1765 sock_release(ndisc_socket);
1766 ndisc_socket = NULL; /* For safety. */
1767}