blob: 79a56a7663b7e634dcabbe900596ffe355a64209 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Neighbour Discovery for IPv6
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003 * Linux INET6 implementation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Mike Shaver <shaver@ingenia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15/*
16 * Changes:
17 *
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +000018 * Alexey I. Froloff : RFC6106 (DNSSL) support
Pierre Ynard31910572007-10-10 21:22:05 -070019 * Pierre Ynard : export userland ND options
20 * through netlink (RDNSS support)
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * Lars Fenneberg : fixed MTU setting on receipt
22 * of an RA.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 * Janos Farkas : kmalloc failure checks
24 * Alexey Kuznetsov : state machine reworked
25 * and moved to net/core.
26 * Pekka Savola : RFC2461 validation
27 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
28 */
29
Joe Perches675418d2012-05-16 19:28:38 +000030#define pr_fmt(fmt) "ICMPv6: " fmt
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/types.h>
35#include <linux/socket.h>
36#include <linux/sockios.h>
37#include <linux/sched.h>
38#include <linux/net.h>
39#include <linux/in6.h>
40#include <linux/route.h>
41#include <linux/init.h>
42#include <linux/rcupdate.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090043#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#ifdef CONFIG_SYSCTL
45#include <linux/sysctl.h>
46#endif
47
Thomas Graf18237302006-08-04 23:04:54 -070048#include <linux/if_addr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/if_arp.h>
50#include <linux/ipv6.h>
51#include <linux/icmpv6.h>
52#include <linux/jhash.h>
53
54#include <net/sock.h>
55#include <net/snmp.h>
56
57#include <net/ipv6.h>
58#include <net/protocol.h>
59#include <net/ndisc.h>
60#include <net/ip6_route.h>
61#include <net/addrconf.h>
62#include <net/icmp.h>
63
Pierre Ynard31910572007-10-10 21:22:05 -070064#include <net/netlink.h>
65#include <linux/rtnetlink.h>
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <net/flow.h>
68#include <net/ip6_checksum.h>
Denis V. Lunev1ed85162008-04-03 14:31:03 -070069#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#include <linux/proc_fs.h>
71
72#include <linux/netfilter.h>
73#include <linux/netfilter_ipv6.h>
74
Joe Perches675418d2012-05-16 19:28:38 +000075/* Set to 3 to get tracing... */
76#define ND_DEBUG 1
77
78#define ND_PRINTK(val, level, fmt, ...) \
79do { \
80 if (val <= ND_DEBUG) \
81 net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
82} while (0)
83
Eric Dumazetd6bf7812010-10-04 06:15:44 +000084static u32 ndisc_hash(const void *pkey,
85 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -050086 __u32 *hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static int ndisc_constructor(struct neighbour *neigh);
88static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
89static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
90static int pndisc_constructor(struct pneigh_entry *n);
91static void pndisc_destructor(struct pneigh_entry *n);
92static void pndisc_redo(struct sk_buff *skb);
93
Stephen Hemminger89d69d22009-09-01 11:13:19 +000094static const struct neigh_ops ndisc_generic_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 .family = AF_INET6,
96 .solicit = ndisc_solicit,
97 .error_report = ndisc_error_report,
98 .output = neigh_resolve_output,
99 .connected_output = neigh_connected_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000102static const struct neigh_ops ndisc_hh_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 .family = AF_INET6,
104 .solicit = ndisc_solicit,
105 .error_report = ndisc_error_report,
106 .output = neigh_resolve_output,
107 .connected_output = neigh_resolve_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
110
Stephen Hemminger89d69d22009-09-01 11:13:19 +0000111static const struct neigh_ops ndisc_direct_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .family = AF_INET6,
David S. Miller8f40b162011-07-17 13:34:11 -0700113 .output = neigh_direct_output,
114 .connected_output = neigh_direct_output,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
117struct neigh_table nd_tbl = {
118 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .key_len = sizeof(struct in6_addr),
120 .hash = ndisc_hash,
121 .constructor = ndisc_constructor,
122 .pconstructor = pndisc_constructor,
123 .pdestructor = pndisc_destructor,
124 .proxy_redo = pndisc_redo,
125 .id = "ndisc_cache",
126 .parms = {
Shan Weib6720832010-12-01 18:05:12 +0000127 .tbl = &nd_tbl,
128 .base_reachable_time = ND_REACHABLE_TIME,
129 .retrans_time = ND_RETRANS_TIMER,
130 .gc_staletime = 60 * HZ,
131 .reachable_time = ND_REACHABLE_TIME,
132 .delay_probe_time = 5 * HZ,
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000133 .queue_len_bytes = 64*1024,
Shan Weib6720832010-12-01 18:05:12 +0000134 .ucast_probes = 3,
135 .mcast_probes = 3,
136 .anycast_delay = 1 * HZ,
137 .proxy_delay = (8 * HZ) / 10,
138 .proxy_qlen = 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 },
140 .gc_interval = 30 * HZ,
141 .gc_thresh1 = 128,
142 .gc_thresh2 = 512,
143 .gc_thresh3 = 1024,
144};
145
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000146static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000148 int pad = ndisc_addr_option_pad(skb->dev->type);
149 int data_len = skb->dev->addr_len;
150 int space = ndisc_opt_addr_space(skb->dev);
151 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153 opt[0] = type;
154 opt[1] = space>>3;
155
156 memset(opt + 2, 0, pad);
157 opt += pad;
158 space -= pad;
159
160 memcpy(opt+2, data, data_len);
161 data_len += 2;
162 opt += data_len;
163 if ((space -= data_len) > 0)
164 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
167static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
168 struct nd_opt_hdr *end)
169{
170 int type;
171 if (!cur || !end || cur >= end)
172 return NULL;
173 type = cur->nd_opt_type;
174 do {
175 cur = ((void *)cur) + (cur->nd_opt_len << 3);
176 } while(cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000177 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178}
179
Pierre Ynard31910572007-10-10 21:22:05 -0700180static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
181{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000182 return opt->nd_opt_type == ND_OPT_RDNSS ||
183 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700184}
185
186static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
187 struct nd_opt_hdr *end)
188{
189 if (!cur || !end || cur >= end)
190 return NULL;
191 do {
192 cur = ((void *)cur) + (cur->nd_opt_len << 3);
193 } while(cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000194 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700195}
196
David S. Miller30f2a5f2012-07-11 23:26:46 -0700197struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
198 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
200 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
201
202 if (!nd_opt || opt_len < 0 || !ndopts)
203 return NULL;
204 memset(ndopts, 0, sizeof(*ndopts));
205 while (opt_len) {
206 int l;
207 if (opt_len < sizeof(struct nd_opt_hdr))
208 return NULL;
209 l = nd_opt->nd_opt_len << 3;
210 if (opt_len < l || l == 0)
211 return NULL;
212 switch (nd_opt->nd_opt_type) {
213 case ND_OPT_SOURCE_LL_ADDR:
214 case ND_OPT_TARGET_LL_ADDR:
215 case ND_OPT_MTU:
216 case ND_OPT_REDIRECT_HDR:
217 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000218 ND_PRINTK(2, warn,
219 "%s: duplicated ND6 option found: type=%d\n",
220 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 } else {
222 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
223 }
224 break;
225 case ND_OPT_PREFIX_INFO:
226 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700227 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
229 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800230#ifdef CONFIG_IPV6_ROUTE_INFO
231 case ND_OPT_ROUTE_INFO:
232 ndopts->nd_opts_ri_end = nd_opt;
233 if (!ndopts->nd_opts_ri)
234 ndopts->nd_opts_ri = nd_opt;
235 break;
236#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700238 if (ndisc_is_useropt(nd_opt)) {
239 ndopts->nd_useropts_end = nd_opt;
240 if (!ndopts->nd_useropts)
241 ndopts->nd_useropts = nd_opt;
242 } else {
243 /*
244 * Unknown options must be silently ignored,
245 * to accommodate future extension to the
246 * protocol.
247 */
Joe Perches675418d2012-05-16 19:28:38 +0000248 ND_PRINTK(2, notice,
249 "%s: ignored unsupported option; type=%d, len=%d\n",
250 __func__,
251 nd_opt->nd_opt_type,
252 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 }
255 opt_len -= l;
256 nd_opt = ((void *)nd_opt) + l;
257 }
258 return ndopts;
259}
260
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000261int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262{
263 switch (dev->type) {
264 case ARPHRD_ETHER:
265 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
266 case ARPHRD_FDDI:
267 ipv6_eth_mc_map(addr, buf);
268 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 case ARPHRD_ARCNET:
270 ipv6_arcnet_mc_map(addr, buf);
271 return 0;
272 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700273 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000275 case ARPHRD_IPGRE:
276 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 default:
278 if (dir) {
279 memcpy(buf, dev->broadcast, dev->addr_len);
280 return 0;
281 }
282 }
283 return -EINVAL;
284}
285
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900286EXPORT_SYMBOL(ndisc_mc_map);
287
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000288static u32 ndisc_hash(const void *pkey,
289 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500290 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
David S. Miller2c2aba62011-12-28 15:06:58 -0500292 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
295static int ndisc_constructor(struct neighbour *neigh)
296{
297 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
298 struct net_device *dev = neigh->dev;
299 struct inet6_dev *in6_dev;
300 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000301 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 in6_dev = in6_dev_get(dev);
304 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return -EINVAL;
306 }
307
308 parms = in6_dev->nd_parms;
309 __neigh_parms_put(neigh->parms);
310 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700313 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 neigh->nud_state = NUD_NOARP;
315 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700316 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 } else {
318 if (is_multicast) {
319 neigh->nud_state = NUD_NOARP;
320 ndisc_mc_map(addr, neigh->ha, dev, 1);
321 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
322 neigh->nud_state = NUD_NOARP;
323 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
324 if (dev->flags&IFF_LOOPBACK)
325 neigh->type = RTN_LOCAL;
326 } else if (dev->flags&IFF_POINTOPOINT) {
327 neigh->nud_state = NUD_NOARP;
328 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
329 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700330 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 neigh->ops = &ndisc_hh_ops;
332 else
333 neigh->ops = &ndisc_generic_ops;
334 if (neigh->nud_state&NUD_VALID)
335 neigh->output = neigh->ops->connected_output;
336 else
337 neigh->output = neigh->ops->output;
338 }
339 in6_dev_put(in6_dev);
340 return 0;
341}
342
343static int pndisc_constructor(struct pneigh_entry *n)
344{
345 struct in6_addr *addr = (struct in6_addr*)&n->key;
346 struct in6_addr maddr;
347 struct net_device *dev = n->dev;
348
349 if (dev == NULL || __in6_dev_get(dev) == NULL)
350 return -EINVAL;
351 addrconf_addr_solict_mult(addr, &maddr);
352 ipv6_dev_mc_inc(dev, &maddr);
353 return 0;
354}
355
356static void pndisc_destructor(struct pneigh_entry *n)
357{
358 struct in6_addr *addr = (struct in6_addr*)&n->key;
359 struct in6_addr maddr;
360 struct net_device *dev = n->dev;
361
362 if (dev == NULL || __in6_dev_get(dev) == NULL)
363 return;
364 addrconf_addr_solict_mult(addr, &maddr);
365 ipv6_dev_mc_dec(dev, &maddr);
366}
367
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000368static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
369 int len)
370{
371 int hlen = LL_RESERVED_SPACE(dev);
372 int tlen = dev->needed_tailroom;
373 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
374 struct sk_buff *skb;
375 int err;
376
377 skb = sock_alloc_send_skb(sk,
378 hlen + sizeof(struct ipv6hdr) + len + tlen,
379 1, &err);
380 if (!skb) {
381 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n",
382 __func__, err);
383 return NULL;
384 }
385
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000386 skb->protocol = htons(ETH_P_IPV6);
387 skb->dev = dev;
388
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000389 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000390 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000391
392 return skb;
393}
394
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000395static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000396 const struct in6_addr *saddr,
397 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000398 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000399{
400 struct ipv6hdr *hdr;
401
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000402 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000403 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000404 hdr = ipv6_hdr(skb);
405
406 ip6_flow_hdr(hdr, 0, 0);
407
408 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000409 hdr->nexthdr = IPPROTO_ICMPV6;
410 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000411
412 hdr->saddr = *saddr;
413 hdr->daddr = *daddr;
414}
415
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900416static struct sk_buff *ndisc_build_skb(struct net_device *dev,
417 const struct in6_addr *daddr,
418 const struct in6_addr *saddr,
419 struct icmp6hdr *icmp6h,
420 const struct in6_addr *target,
421 int llinfo)
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900422{
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900423 struct sk_buff *skb;
424 struct icmp6hdr *hdr;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900425 int len;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +0000426 int optlen = 0;
Brian Haley305d5522008-11-04 17:51:14 -0800427 u8 *opt;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900428
429 if (!dev->addr_len)
430 llinfo = 0;
431
432 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
433 if (llinfo)
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +0000434 optlen += ndisc_opt_addr_space(dev);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900435
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +0000436 skb = ndisc_alloc_skb(dev, len + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000437 if (!skb)
Brian Haley305d5522008-11-04 17:51:14 -0800438 return NULL;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900439
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000440 skb_put(skb, len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900441
442 hdr = (struct icmp6hdr *)skb_transport_header(skb);
443 memcpy(hdr, icmp6h, sizeof(*hdr));
444
445 opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
446 if (target) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000447 *(struct in6_addr *)opt = *target;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900448 opt += sizeof(*target);
449 }
450
451 if (llinfo)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000452 ndisc_fill_addr_option(skb, llinfo, dev->dev_addr);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900453
Brian Haley305d5522008-11-04 17:51:14 -0800454 return skb;
455}
456
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000457static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900458 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000459 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800460{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000461 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000462 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000463 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800464 struct inet6_dev *idev;
465 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000466 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800467 u8 type;
468
469 type = icmp6h->icmp6_type;
470
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000471 if (!dst) {
472 struct sock *sk = net->ipv6.ndisc_sk;
473 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800474
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000475 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
476 dst = icmp6_dst_alloc(skb->dev, &fl6);
477 if (IS_ERR(dst)) {
478 kfree_skb(skb);
479 return;
480 }
481
482 skb_dst_set(skb, dst);
483 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900484
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000485 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
486 IPPROTO_ICMPV6,
487 csum_partial(icmp6h,
488 skb->len, 0));
489
490 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
491
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000492 rcu_read_lock();
493 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700494 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900495
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100496 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800497 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900498 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700499 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700500 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900501 }
502
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000503 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900504}
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900507 const struct in6_addr *daddr,
508 const struct in6_addr *solicited_addr,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000509 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000511 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 struct in6_addr tmpaddr;
513 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900514 const struct in6_addr *src_addr;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900515 struct icmp6hdr icmp6h = {
516 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
517 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900520 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900521 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700523 if (ifp->flags & IFA_F_OPTIMISTIC)
524 override = 0;
stephen hemminger9f888162010-06-21 11:00:13 +0000525 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 in6_ifa_put(ifp);
527 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700528 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900529 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900530 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return;
532 src_addr = &tmpaddr;
533 }
534
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900535 icmp6h.icmp6_router = router;
536 icmp6h.icmp6_solicited = solicited;
537 icmp6h.icmp6_override = override;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000539 skb = ndisc_build_skb(dev, daddr, src_addr, &icmp6h, solicited_addr,
540 inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
541 if (!skb)
542 return;
543
544 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900545}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000547static void ndisc_send_unsol_na(struct net_device *dev)
548{
549 struct inet6_dev *idev;
550 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000551
552 idev = in6_dev_get(dev);
553 if (!idev)
554 return;
555
556 read_lock_bh(&idev->lock);
557 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000558 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000559 /*router=*/ !!idev->cnf.forwarding,
560 /*solicited=*/ false, /*override=*/ true,
561 /*inc_opt=*/ true);
562 }
563 read_unlock_bh(&idev->lock);
564
565 in6_dev_put(idev);
566}
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900569 const struct in6_addr *solicit,
570 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000572 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 struct in6_addr addr_buf;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900574 struct icmp6hdr icmp6h = {
575 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
576 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700579 if (ipv6_get_lladdr(dev, &addr_buf,
580 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 return;
582 saddr = &addr_buf;
583 }
584
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000585 skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, solicit,
586 !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
587 if (!skb)
588 return;
589
590 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591}
592
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900593void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
594 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000596 struct sk_buff *skb;
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900597 struct icmp6hdr icmp6h = {
598 .icmp6_type = NDISC_ROUTER_SOLICITATION,
599 };
Neil Horman95c385b2007-04-25 17:08:10 -0700600 int send_sllao = dev->addr_len;
Neil Horman95c385b2007-04-25 17:08:10 -0700601
602#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
603 /*
604 * According to section 2.2 of RFC 4429, we must not
605 * send router solicitations with a sllao from
606 * optimistic addresses, but we may send the solicitation
607 * if we don't include the sllao. So here we check
608 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800609 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700610 */
611 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900612 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800613 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700614 if (ifp) {
615 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900616 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700617 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900618 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700619 } else {
620 send_sllao = 0;
621 }
622 }
623#endif
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000624 skb = ndisc_build_skb(dev, daddr, saddr, &icmp6h, NULL,
625 send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
626 if (!skb)
627 return;
628
629 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
634{
635 /*
636 * "The sender MUST return an ICMP
637 * destination unreachable"
638 */
639 dst_link_failure(skb);
640 kfree_skb(skb);
641}
642
643/* Called with locked neigh: either read or both */
644
645static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
646{
647 struct in6_addr *saddr = NULL;
648 struct in6_addr mcaddr;
649 struct net_device *dev = neigh->dev;
650 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
651 int probes = atomic_read(&neigh->probes);
652
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900653 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700654 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 if ((probes -= neigh->parms->ucast_probes) < 0) {
657 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000658 ND_PRINTK(1, dbg,
659 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
660 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
662 ndisc_send_ns(dev, neigh, target, target, saddr);
663 } else if ((probes -= neigh->parms->app_probes) < 0) {
664#ifdef CONFIG_ARPD
665 neigh_app_ns(neigh);
666#endif
667 } else {
668 addrconf_addr_solict_mult(target, &mcaddr);
669 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
670 }
671}
672
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900673static int pndisc_is_router(const void *pkey,
674 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700675{
676 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900677 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700678
679 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900680 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
681 if (n)
682 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700683 read_unlock_bh(&nd_tbl.lock);
684
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900685 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700686}
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688static void ndisc_recv_ns(struct sk_buff *skb)
689{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700690 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000691 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
692 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700694 u32 ndoptlen = skb->tail - (skb->transport_header +
695 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 struct ndisc_options ndopts;
697 struct net_device *dev = skb->dev;
698 struct inet6_ifaddr *ifp;
699 struct inet6_dev *idev = NULL;
700 struct neighbour *neigh;
701 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000702 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900703 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000705 if (skb->len < sizeof(struct nd_msg)) {
706 ND_PRINTK(2, warn, "NS: packet too short\n");
707 return;
708 }
709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000711 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return;
713 }
714
715 /*
716 * RFC2461 7.1.1:
717 * DAD has to be destined for solicited node multicast address.
718 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000719 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000720 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return;
722 }
723
724 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000725 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return;
727 }
728
729 if (ndopts.nd_opts_src_lladdr) {
730 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
731 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000732 ND_PRINTK(2, warn,
733 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return;
735 }
736
737 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900738 * If the IP source address is the unspecified address,
739 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 * in the message.
741 */
742 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000743 ND_PRINTK(2, warn,
744 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return;
746 }
747 }
748
749 inc = ipv6_addr_is_multicast(daddr);
750
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900751 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800752 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700753
754 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
755 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700756 /*
757 * We are colliding with another node
758 * who is doing DAD
759 * so fail our DAD process
760 */
761 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200762 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700763 } else {
764 /*
765 * This is not a dad solicitation.
766 * If we are an optimistic node,
767 * we should respond.
768 * Otherwise, we should ignore it.
769 */
770 if (!(ifp->flags & IFA_F_OPTIMISTIC))
771 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774
775 idev = ifp->idev;
776 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700777 struct net *net = dev_net(dev);
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 idev = in6_dev_get(dev);
780 if (!idev) {
781 /* XXX: count this drop? */
782 return;
783 }
784
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700785 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900786 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700787 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900788 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700789 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 skb->pkt_type != PACKET_HOST &&
791 inc != 0 &&
792 idev->nd_parms->proxy_delay != 0) {
793 /*
794 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900795 * sender should delay its response
796 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 * MAX_ANYCAST_DELAY_TIME seconds.
798 * (RFC2461) -- yoshfuji
799 */
800 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
801 if (n)
802 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
803 goto out;
804 }
805 } else
806 goto out;
807 }
808
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900809 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000810 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900813 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000814 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 goto out;
816 }
817
818 if (inc)
819 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
820 else
821 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
822
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900823 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * update / create cache entry
825 * for the source address
826 */
827 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
828 !inc || lladdr || !dev->addr_len);
829 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900830 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 NEIGH_UPDATE_F_WEAK_OVERRIDE|
832 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700833 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000835 !!is_router,
836 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (neigh)
838 neigh_release(neigh);
839 }
840
841out:
842 if (ifp)
843 in6_ifa_put(ifp);
844 else
845 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846}
847
848static void ndisc_recv_na(struct sk_buff *skb)
849{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700850 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000851 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
852 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 u8 *lladdr = NULL;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700854 u32 ndoptlen = skb->tail - (skb->transport_header +
855 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 struct ndisc_options ndopts;
857 struct net_device *dev = skb->dev;
858 struct inet6_ifaddr *ifp;
859 struct neighbour *neigh;
860
861 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000862 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return;
864 }
865
866 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000867 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return;
869 }
870
871 if (ipv6_addr_is_multicast(daddr) &&
872 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000873 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return;
875 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000878 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return;
880 }
881 if (ndopts.nd_opts_tgt_lladdr) {
882 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
883 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000884 ND_PRINTK(2, warn,
885 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return;
887 }
888 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900889 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800890 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000891 if (skb->pkt_type != PACKET_LOOPBACK
892 && (ifp->flags & IFA_F_TENTATIVE)) {
893 addrconf_dad_failure(ifp);
894 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 }
896 /* What should we make now? The advertisement
897 is invalid, but ndisc specs say nothing
898 about it. It could be misconfiguration, or
899 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800900
901 We should not print the error if NA has been
902 received from loopback - it is just our own
903 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800905 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000906 ND_PRINTK(1, warn,
907 "NA: someone advertises our address %pI6 on %s!\n",
908 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 in6_ifa_put(ifp);
910 return;
911 }
912 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
913
914 if (neigh) {
915 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700916 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 if (neigh->nud_state & NUD_FAILED)
919 goto out;
920
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700921 /*
922 * Don't update the neighbor cache entry on a proxy NA from
923 * ourselves because either the proxied node is off link or it
924 * has already sent a NA to us.
925 */
926 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700927 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
928 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000929 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700930 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700931 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 neigh_update(neigh, lladdr,
934 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
935 NEIGH_UPDATE_F_WEAK_OVERRIDE|
936 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
937 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
938 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
939
940 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
941 /*
942 * Change: router to host
943 */
944 struct rt6_info *rt;
945 rt = rt6_get_dflt_router(saddr, dev);
946 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700947 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949
950out:
951 neigh_release(neigh);
952 }
953}
954
955static void ndisc_recv_rs(struct sk_buff *skb)
956{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700957 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
959 struct neighbour *neigh;
960 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000961 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 struct ndisc_options ndopts;
963 u8 *lladdr = NULL;
964
965 if (skb->len < sizeof(*rs_msg))
966 return;
967
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000968 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000970 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return;
972 }
973
974 /* Don't accept RS if we're not in router mode */
975 if (!idev->cnf.forwarding)
976 goto out;
977
978 /*
979 * Don't update NCE if src = ::;
980 * this implies that the source node has no ip address assigned yet.
981 */
982 if (ipv6_addr_any(saddr))
983 goto out;
984
985 /* Parse ND options */
986 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000987 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 goto out;
989 }
990
991 if (ndopts.nd_opts_src_lladdr) {
992 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
993 skb->dev);
994 if (!lladdr)
995 goto out;
996 }
997
998 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
999 if (neigh) {
1000 neigh_update(neigh, lladdr, NUD_STALE,
1001 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1002 NEIGH_UPDATE_F_OVERRIDE|
1003 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1004 neigh_release(neigh);
1005 }
1006out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
Pierre Ynard31910572007-10-10 21:22:05 -07001010static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1011{
1012 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1013 struct sk_buff *skb;
1014 struct nlmsghdr *nlh;
1015 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001016 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001017 int err;
1018 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1019 + (opt->nd_opt_len << 3));
1020 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1021
1022 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1023 if (skb == NULL) {
1024 err = -ENOBUFS;
1025 goto errout;
1026 }
1027
1028 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1029 if (nlh == NULL) {
1030 goto nla_put_failure;
1031 }
1032
1033 ndmsg = nlmsg_data(nlh);
1034 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001035 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001036 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1037 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1038 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1039
1040 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1041
David S. Millerc78679e2012-04-01 20:27:33 -04001042 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1043 &ipv6_hdr(ra)->saddr))
1044 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001045 nlmsg_end(skb, nlh);
1046
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001047 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001048 return;
1049
1050nla_put_failure:
1051 nlmsg_free(skb);
1052 err = -EMSGSIZE;
1053errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001054 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001055}
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057static void ndisc_router_discovery(struct sk_buff *skb)
1058{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001059 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 struct neighbour *neigh = NULL;
1061 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001062 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 int lifetime;
1064 struct ndisc_options ndopts;
1065 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001066 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 __u8 * opt = (__u8 *)(ra_msg + 1);
1069
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001070 optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001072 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001073 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 return;
1075 }
1076 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001077 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return;
1079 }
1080
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001081#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001082 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001083 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001084 return;
1085 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001086#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /*
1089 * set the RA_RECV flag in the interface
1090 */
1091
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001092 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001094 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1095 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return;
1097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001100 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return;
1102 }
1103
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001104 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001105 goto skip_linkparms;
1106
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001107#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001108 /* skip link-specific parameters from interior routers */
1109 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1110 goto skip_linkparms;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001111#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001112
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 if (in6_dev->if_flags & IF_RS_SENT) {
1114 /*
1115 * flag that an RA was received after an RS was sent
1116 * out on this interface.
1117 */
1118 in6_dev->if_flags |= IF_RA_RCVD;
1119 }
1120
1121 /*
1122 * Remember the managed/otherconf flags from most recently
1123 * received RA message (RFC 2462) -- yoshfuji
1124 */
1125 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1126 IF_RA_OTHERCONF)) |
1127 (ra_msg->icmph.icmp6_addrconf_managed ?
1128 IF_RA_MANAGED : 0) |
1129 (ra_msg->icmph.icmp6_addrconf_other ?
1130 IF_RA_OTHERCONF : 0);
1131
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001132 if (!in6_dev->cnf.accept_ra_defrtr)
1133 goto skip_defrtr;
1134
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001135 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1136 goto skip_defrtr;
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1139
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001140#ifdef CONFIG_IPV6_ROUTER_PREF
1141 pref = ra_msg->icmph.icmp6_router_pref;
1142 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001143 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001144 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001145 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1146#endif
1147
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001148 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
David S. Millereb857182012-01-27 15:07:56 -08001150 if (rt) {
1151 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1152 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001153 ND_PRINTK(0, err,
1154 "RA: %s got default router without neighbour\n",
1155 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001156 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001157 return;
1158 }
1159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001161 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 rt = NULL;
1163 }
1164
1165 if (rt == NULL && lifetime) {
Joe Perches675418d2012-05-16 19:28:38 +00001166 ND_PRINTK(3, dbg, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001168 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001170 ND_PRINTK(0, err,
1171 "RA: %s failed to add default route\n",
1172 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 return;
1174 }
1175
David S. Millereb857182012-01-27 15:07:56 -08001176 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001178 ND_PRINTK(0, err,
1179 "RA: %s got default router without neighbour\n",
1180 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001181 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return;
1183 }
1184 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001185 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001186 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188
1189 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001190 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (ra_msg->icmph.icmp6_hop_limit) {
1192 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1193 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001194 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1195 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 }
1197
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001198skip_defrtr:
1199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 /*
1201 * Update Reachable Time and Retrans Timer
1202 */
1203
1204 if (in6_dev->nd_parms) {
1205 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1206
1207 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1208 rtime = (rtime*HZ)/1000;
1209 if (rtime < HZ/10)
1210 rtime = HZ/10;
1211 in6_dev->nd_parms->retrans_time = rtime;
1212 in6_dev->tstamp = jiffies;
1213 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1214 }
1215
1216 rtime = ntohl(ra_msg->reachable_time);
1217 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1218 rtime = (rtime*HZ)/1000;
1219
1220 if (rtime < HZ/10)
1221 rtime = HZ/10;
1222
1223 if (rtime != in6_dev->nd_parms->base_reachable_time) {
1224 in6_dev->nd_parms->base_reachable_time = rtime;
1225 in6_dev->nd_parms->gc_staletime = 3 * rtime;
1226 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1227 in6_dev->tstamp = jiffies;
1228 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1229 }
1230 }
1231 }
1232
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001233skip_linkparms:
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 /*
1236 * Process options.
1237 */
1238
1239 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001240 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 skb->dev, 1);
1242 if (neigh) {
1243 u8 *lladdr = NULL;
1244 if (ndopts.nd_opts_src_lladdr) {
1245 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1246 skb->dev);
1247 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001248 ND_PRINTK(2, warn,
1249 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 goto out;
1251 }
1252 }
1253 neigh_update(neigh, lladdr, NUD_STALE,
1254 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1255 NEIGH_UPDATE_F_OVERRIDE|
1256 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1257 NEIGH_UPDATE_F_ISROUTER);
1258 }
1259
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001260 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001261 goto out;
1262
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001263#ifdef CONFIG_IPV6_ROUTE_INFO
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001264 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1265 goto skip_routeinfo;
1266
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001267 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001268 struct nd_opt_hdr *p;
1269 for (p = ndopts.nd_opts_ri;
1270 p;
1271 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001272 struct route_info *ri = (struct route_info *)p;
1273#ifdef CONFIG_IPV6_NDISC_NODETYPE
1274 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1275 ri->prefix_len == 0)
1276 continue;
1277#endif
1278 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001279 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001280 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001281 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001282 }
1283 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001284
1285skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001286#endif
1287
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001288#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001289 /* skip link-specific ndopts from interior routers */
1290 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1291 goto out;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001292#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001293
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001294 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 struct nd_opt_hdr *p;
1296 for (p = ndopts.nd_opts_pi;
1297 p;
1298 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001299 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1300 (p->nd_opt_len) << 3,
1301 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 }
1303 }
1304
1305 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001306 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 u32 mtu;
1308
Al Viroe69a4adc2006-11-14 20:56:00 -08001309 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1310 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001313 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 } else if (in6_dev->cnf.mtu6 != mtu) {
1315 in6_dev->cnf.mtu6 = mtu;
1316
1317 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001318 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 rt6_mtu_change(skb->dev, mtu);
1321 }
1322 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001323
Pierre Ynard31910572007-10-10 21:22:05 -07001324 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001325 struct nd_opt_hdr *p;
1326 for (p = ndopts.nd_useropts;
1327 p;
1328 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1329 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001330 }
1331 }
1332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001334 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
1336out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001337 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001338 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340}
1341
1342static void ndisc_redirect_rcv(struct sk_buff *skb)
1343{
Duan Jiong093d04d2012-12-14 02:59:59 +00001344 u8 *hdr;
1345 struct ndisc_options ndopts;
1346 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
1347 u32 ndoptlen = skb->tail - (skb->transport_header +
1348 offsetof(struct rd_msg, opt));
1349
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001350#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001351 switch (skb->ndisc_nodetype) {
1352 case NDISC_NODETYPE_HOST:
1353 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001354 ND_PRINTK(2, warn,
1355 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001356 return;
1357 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001358#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001359
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001360 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001361 ND_PRINTK(2, warn,
1362 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 return;
1364 }
1365
Duan Jiong093d04d2012-12-14 02:59:59 +00001366 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1367 return;
1368
1369 if (!ndopts.nd_opts_rh)
1370 return;
1371
1372 hdr = (u8 *)ndopts.nd_opts_rh;
1373 hdr += 8;
1374 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1375 return;
1376
David S. Millerb94f1c02012-07-12 00:33:37 -07001377 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378}
1379
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001380static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1381 struct sk_buff *orig_skb,
1382 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001383{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001384 u8 *opt = skb_put(skb, rd_len);
1385
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001386 memset(opt, 0, 8);
1387 *(opt++) = ND_OPT_REDIRECT_HDR;
1388 *(opt++) = (rd_len >> 3);
1389 opt += 6;
1390
1391 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001392}
1393
David S. Miller49919692012-01-27 15:30:48 -08001394void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001396 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001397 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001398 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001399 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001400 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001402 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 struct rt6_info *rt;
1405 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001406 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001409 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Neil Horman95c385b2007-04-25 17:08:10 -07001411 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001412 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1413 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001414 return;
1415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001417 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001418 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001419 ND_PRINTK(2, warn,
1420 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001421 return;
1422 }
1423
David S. Miller4c9483b2011-03-12 16:22:43 -05001424 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001425 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
David S. Miller4c9483b2011-03-12 16:22:43 -05001427 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001428 if (dst->error) {
1429 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001431 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001432 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001433 if (IS_ERR(dst))
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) {
Joe Perches675418d2012-05-16 19:28:38 +00001439 ND_PRINTK(2, warn,
1440 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001441 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001443 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1444 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1445 if (peer)
1446 inet_putpeer(peer);
1447 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001448 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
1450 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001451 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1452 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001453 ND_PRINTK(2, warn,
1454 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001455 goto release;
1456 }
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 read_lock_bh(&neigh->lock);
1459 if (neigh->nud_state & NUD_VALID) {
1460 memcpy(ha_buf, neigh->ha, dev->addr_len);
1461 read_unlock_bh(&neigh->lock);
1462 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001463 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 } else
1465 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001466
1467 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469
1470 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001471 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1472 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001474 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001476 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001477 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001478 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001480 skb_put(buff, sizeof(*msg));
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001481 msg = (struct rd_msg *)icmp6_hdr(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001483 memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
1484 msg->icmph.icmp6_type = NDISC_REDIRECT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 /*
1487 * copy target and destination addresses
1488 */
1489
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001490 msg->target = *target;
1491 msg->dest = ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 /*
1494 * include target_address option
1495 */
1496
1497 if (ha)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001498 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 /*
1501 * build redirect option and copy skb over to the new packet.
1502 */
1503
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001504 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001505 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Eric Dumazetadf30902009-06-02 05:19:30 +00001507 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001508 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001509 return;
1510
1511release:
1512 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513}
1514
1515static void pndisc_redo(struct sk_buff *skb)
1516{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001517 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 kfree_skb(skb);
1519}
1520
1521int ndisc_rcv(struct sk_buff *skb)
1522{
1523 struct nd_msg *msg;
1524
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001525 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 return 0;
1527
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001528 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001530 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001532 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001533 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1534 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 return 0;
1536 }
1537
1538 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001539 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1540 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 return 0;
1542 }
1543
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001544 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 switch (msg->icmph.icmp6_type) {
1547 case NDISC_NEIGHBOUR_SOLICITATION:
1548 ndisc_recv_ns(skb);
1549 break;
1550
1551 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1552 ndisc_recv_na(skb);
1553 break;
1554
1555 case NDISC_ROUTER_SOLICITATION:
1556 ndisc_recv_rs(skb);
1557 break;
1558
1559 case NDISC_ROUTER_ADVERTISEMENT:
1560 ndisc_router_discovery(skb);
1561 break;
1562
1563 case NDISC_REDIRECT:
1564 ndisc_redirect_rcv(skb);
1565 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 return 0;
1569}
1570
1571static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1572{
1573 struct net_device *dev = ptr;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001574 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001575 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
1577 switch (event) {
1578 case NETDEV_CHANGEADDR:
1579 neigh_changeaddr(&nd_tbl, dev);
Daniel Lezcano5b7c9312008-03-03 23:28:58 -08001580 fib6_run_gc(~0UL, net);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001581 idev = in6_dev_get(dev);
1582 if (!idev)
1583 break;
1584 if (idev->cnf.ndisc_notify)
1585 ndisc_send_unsol_na(dev);
1586 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 break;
1588 case NETDEV_DOWN:
1589 neigh_ifdown(&nd_tbl, dev);
Daniel Lezcano5b7c9312008-03-03 23:28:58 -08001590 fib6_run_gc(~0UL, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001592 case NETDEV_NOTIFY_PEERS:
1593 ndisc_send_unsol_na(dev);
1594 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 default:
1596 break;
1597 }
1598
1599 return NOTIFY_DONE;
1600}
1601
1602static struct notifier_block ndisc_netdev_notifier = {
1603 .notifier_call = ndisc_netdev_event,
1604};
1605
1606#ifdef CONFIG_SYSCTL
1607static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1608 const char *func, const char *dev_name)
1609{
1610 static char warncomm[TASK_COMM_LEN];
1611 static int warned;
1612 if (strcmp(warncomm, current->comm) && warned < 5) {
1613 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001614 pr_warn("process `%s' is using deprecated sysctl (%s) net.ipv6.neigh.%s.%s - use net.ipv6.neigh.%s.%s_ms instead\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 warncomm, func,
1616 dev_name, ctl->procname,
1617 dev_name, ctl->procname);
1618 warned++;
1619 }
1620}
1621
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001622int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623{
1624 struct net_device *dev = ctl->extra1;
1625 struct inet6_dev *idev;
1626 int ret;
1627
Eric W. Biedermand12af672007-10-18 03:05:25 -07001628 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1629 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1631
Eric W. Biedermand12af672007-10-18 03:05:25 -07001632 if (strcmp(ctl->procname, "retrans_time") == 0)
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001633 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001634
1635 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 ret = proc_dointvec_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001637 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001638
1639 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001640 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 ret = proc_dointvec_ms_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001642 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001643 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Eric W. Biedermand12af672007-10-18 03:05:25 -07001647 if (ctl->data == &idev->nd_parms->base_reachable_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1649 idev->tstamp = jiffies;
1650 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1651 in6_dev_put(idev);
1652 }
1653 return ret;
1654}
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657#endif
1658
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001659static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
1661 struct ipv6_pinfo *np;
1662 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001663 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001665 err = inet_ctl_sock_create(&sk, PF_INET6,
1666 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001668 ND_PRINTK(0, err,
1669 "NDISC: Failed to initialize the control socket (err %d)\n",
1670 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 return err;
1672 }
1673
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001674 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 np->hop_limit = 255;
1678 /* Do not loopback ndisc messages */
1679 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001681 return 0;
1682}
1683
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001684static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001685{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001686 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001687}
1688
1689static struct pernet_operations ndisc_net_ops = {
1690 .init = ndisc_net_init,
1691 .exit = ndisc_net_exit,
1692};
1693
1694int __init ndisc_init(void)
1695{
1696 int err;
1697
1698 err = register_pernet_subsys(&ndisc_net_ops);
1699 if (err)
1700 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001701 /*
1702 * Initialize the neighbour table
1703 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 neigh_table_init(&nd_tbl);
1705
1706#ifdef CONFIG_SYSCTL
Eric W. Biederman54716e32010-02-14 03:27:03 +00001707 err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001708 &ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001709 if (err)
1710 goto out_unregister_pernet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001712 err = register_netdevice_notifier(&ndisc_netdev_notifier);
1713 if (err)
1714 goto out_unregister_sysctl;
1715out:
1716 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001718out_unregister_sysctl:
1719#ifdef CONFIG_SYSCTL
1720 neigh_sysctl_unregister(&nd_tbl.parms);
1721out_unregister_pernet:
1722#endif
1723 unregister_pernet_subsys(&ndisc_net_ops);
1724 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725}
1726
1727void ndisc_cleanup(void)
1728{
Dmitry Mishin36f73d02006-11-03 16:08:19 -08001729 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730#ifdef CONFIG_SYSCTL
1731 neigh_sysctl_unregister(&nd_tbl.parms);
1732#endif
1733 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001734 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735}