blob: c4bc7a35cd56f54eb543b68c2c081370cc50f3c0 [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 Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000416static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900417 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000418 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800419{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000420 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000421 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000422 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800423 struct inet6_dev *idev;
424 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000425 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800426 u8 type;
427
428 type = icmp6h->icmp6_type;
429
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000430 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000431 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800432
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000433 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
434 dst = icmp6_dst_alloc(skb->dev, &fl6);
435 if (IS_ERR(dst)) {
436 kfree_skb(skb);
437 return;
438 }
439
440 skb_dst_set(skb, dst);
441 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900442
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000443 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
444 IPPROTO_ICMPV6,
445 csum_partial(icmp6h,
446 skb->len, 0));
447
448 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
449
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000450 rcu_read_lock();
451 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700452 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900453
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100454 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800455 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900456 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700457 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700458 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900459 }
460
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000461 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900462}
463
Cong Wangf564f452013-08-31 13:44:36 +0800464void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
465 const struct in6_addr *daddr,
466 const struct in6_addr *solicited_addr,
467 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000469 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 struct in6_addr tmpaddr;
471 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900472 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000473 struct nd_msg *msg;
474 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900477 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900478 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700480 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300481 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000482 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 in6_ifa_put(ifp);
484 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700485 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900486 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900487 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return;
489 src_addr = &tmpaddr;
490 }
491
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000492 if (!dev->addr_len)
493 inc_opt = 0;
494 if (inc_opt)
495 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000497 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000498 if (!skb)
499 return;
500
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000501 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
502 *msg = (struct nd_msg) {
503 .icmph = {
504 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
505 .icmp6_router = router,
506 .icmp6_solicited = solicited,
507 .icmp6_override = override,
508 },
509 .target = *solicited_addr,
510 };
511
512 if (inc_opt)
513 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
514 dev->dev_addr);
515
516
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000517 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900518}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000520static void ndisc_send_unsol_na(struct net_device *dev)
521{
522 struct inet6_dev *idev;
523 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000524
525 idev = in6_dev_get(dev);
526 if (!idev)
527 return;
528
529 read_lock_bh(&idev->lock);
530 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000531 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000532 /*router=*/ !!idev->cnf.forwarding,
533 /*solicited=*/ false, /*override=*/ true,
534 /*inc_opt=*/ true);
535 }
536 read_unlock_bh(&idev->lock);
537
538 in6_dev_put(idev);
539}
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900542 const struct in6_addr *solicit,
543 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000545 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000547 int inc_opt = dev->addr_len;
548 int optlen = 0;
549 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700552 if (ipv6_get_lladdr(dev, &addr_buf,
553 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return;
555 saddr = &addr_buf;
556 }
557
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000558 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300559 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000560 if (inc_opt)
561 optlen += ndisc_opt_addr_space(dev);
562
563 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000564 if (!skb)
565 return;
566
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000567 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
568 *msg = (struct nd_msg) {
569 .icmph = {
570 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
571 },
572 .target = *solicit,
573 };
574
575 if (inc_opt)
576 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
577 dev->dev_addr);
578
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000579 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900582void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
583 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000585 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000586 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700587 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000588 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700589
590#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
591 /*
592 * According to section 2.2 of RFC 4429, we must not
593 * send router solicitations with a sllao from
594 * optimistic addresses, but we may send the solicitation
595 * if we don't include the sllao. So here we check
596 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800597 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700598 */
599 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900600 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800601 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700602 if (ifp) {
603 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900604 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700605 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900606 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700607 } else {
608 send_sllao = 0;
609 }
610 }
611#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000612 if (send_sllao)
613 optlen += ndisc_opt_addr_space(dev);
614
615 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000616 if (!skb)
617 return;
618
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000619 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
620 *msg = (struct rs_msg) {
621 .icmph = {
622 .icmp6_type = NDISC_ROUTER_SOLICITATION,
623 },
624 };
625
626 if (send_sllao)
627 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
628 dev->dev_addr);
629
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000630 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
635{
636 /*
637 * "The sender MUST return an ICMP
638 * destination unreachable"
639 */
640 dst_link_failure(skb);
641 kfree_skb(skb);
642}
643
644/* Called with locked neigh: either read or both */
645
646static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
647{
648 struct in6_addr *saddr = NULL;
649 struct in6_addr mcaddr;
650 struct net_device *dev = neigh->dev;
651 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
652 int probes = atomic_read(&neigh->probes);
653
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900654 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700655 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 if ((probes -= neigh->parms->ucast_probes) < 0) {
658 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000659 ND_PRINTK(1, dbg,
660 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
661 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
663 ndisc_send_ns(dev, neigh, target, target, saddr);
664 } else if ((probes -= neigh->parms->app_probes) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 } else {
667 addrconf_addr_solict_mult(target, &mcaddr);
668 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
669 }
670}
671
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900672static int pndisc_is_router(const void *pkey,
673 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700674{
675 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900676 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700677
678 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900679 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
680 if (n)
681 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700682 read_unlock_bh(&nd_tbl.lock);
683
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900684 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700685}
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static void ndisc_recv_ns(struct sk_buff *skb)
688{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700689 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000690 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
691 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000693 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700694 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 struct ndisc_options ndopts;
696 struct net_device *dev = skb->dev;
697 struct inet6_ifaddr *ifp;
698 struct inet6_dev *idev = NULL;
699 struct neighbour *neigh;
700 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000701 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900702 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000704 if (skb->len < sizeof(struct nd_msg)) {
705 ND_PRINTK(2, warn, "NS: packet too short\n");
706 return;
707 }
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000710 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return;
712 }
713
714 /*
715 * RFC2461 7.1.1:
716 * DAD has to be destined for solicited node multicast address.
717 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000718 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000719 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return;
721 }
722
723 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000724 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return;
726 }
727
728 if (ndopts.nd_opts_src_lladdr) {
729 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
730 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000731 ND_PRINTK(2, warn,
732 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return;
734 }
735
736 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900737 * If the IP source address is the unspecified address,
738 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 * in the message.
740 */
741 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000742 ND_PRINTK(2, warn,
743 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return;
745 }
746 }
747
748 inc = ipv6_addr_is_multicast(daddr);
749
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900750 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800751 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700752
753 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
754 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700755 /*
756 * We are colliding with another node
757 * who is doing DAD
758 * so fail our DAD process
759 */
760 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200761 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700762 } else {
763 /*
764 * This is not a dad solicitation.
765 * If we are an optimistic node,
766 * we should respond.
767 * Otherwise, we should ignore it.
768 */
769 if (!(ifp->flags & IFA_F_OPTIMISTIC))
770 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
773
774 idev = ifp->idev;
775 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700776 struct net *net = dev_net(dev);
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 idev = in6_dev_get(dev);
779 if (!idev) {
780 /* XXX: count this drop? */
781 return;
782 }
783
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700784 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900785 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700786 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900787 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700788 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300790 inc &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 idev->nd_parms->proxy_delay != 0) {
792 /*
793 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900794 * sender should delay its response
795 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 * MAX_ANYCAST_DELAY_TIME seconds.
797 * (RFC2461) -- yoshfuji
798 */
799 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
800 if (n)
801 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
802 goto out;
803 }
804 } else
805 goto out;
806 }
807
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900808 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000809 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900812 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000813 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 goto out;
815 }
816
817 if (inc)
818 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
819 else
820 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
821
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900822 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 * update / create cache entry
824 * for the source address
825 */
826 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
827 !inc || lladdr || !dev->addr_len);
828 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900829 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 NEIGH_UPDATE_F_WEAK_OVERRIDE|
831 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700832 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000834 !!is_router,
835 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (neigh)
837 neigh_release(neigh);
838 }
839
840out:
841 if (ifp)
842 in6_ifa_put(ifp);
843 else
844 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845}
846
847static void ndisc_recv_na(struct sk_buff *skb)
848{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700849 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000850 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
851 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000853 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700854 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 struct ndisc_options ndopts;
856 struct net_device *dev = skb->dev;
857 struct inet6_ifaddr *ifp;
858 struct neighbour *neigh;
859
860 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000861 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return;
863 }
864
865 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000866 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 return;
868 }
869
870 if (ipv6_addr_is_multicast(daddr) &&
871 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000872 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return;
874 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000877 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return;
879 }
880 if (ndopts.nd_opts_tgt_lladdr) {
881 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
882 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000883 ND_PRINTK(2, warn,
884 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return;
886 }
887 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900888 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800889 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000890 if (skb->pkt_type != PACKET_LOOPBACK
891 && (ifp->flags & IFA_F_TENTATIVE)) {
892 addrconf_dad_failure(ifp);
893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 }
895 /* What should we make now? The advertisement
896 is invalid, but ndisc specs say nothing
897 about it. It could be misconfiguration, or
898 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800899
900 We should not print the error if NA has been
901 received from loopback - it is just our own
902 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800904 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000905 ND_PRINTK(1, warn,
906 "NA: someone advertises our address %pI6 on %s!\n",
907 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 in6_ifa_put(ifp);
909 return;
910 }
911 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
912
913 if (neigh) {
914 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700915 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 if (neigh->nud_state & NUD_FAILED)
918 goto out;
919
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700920 /*
921 * Don't update the neighbor cache entry on a proxy NA from
922 * ourselves because either the proxied node is off link or it
923 * has already sent a NA to us.
924 */
925 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700926 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
927 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000928 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700929 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700930 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 neigh_update(neigh, lladdr,
933 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
934 NEIGH_UPDATE_F_WEAK_OVERRIDE|
935 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
936 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
937 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
938
939 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
940 /*
941 * Change: router to host
942 */
943 struct rt6_info *rt;
944 rt = rt6_get_dflt_router(saddr, dev);
945 if (rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700946 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 }
948
949out:
950 neigh_release(neigh);
951 }
952}
953
954static void ndisc_recv_rs(struct sk_buff *skb)
955{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700956 struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
958 struct neighbour *neigh;
959 struct inet6_dev *idev;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000960 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 struct ndisc_options ndopts;
962 u8 *lladdr = NULL;
963
964 if (skb->len < sizeof(*rs_msg))
965 return;
966
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000967 idev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (!idev) {
Joe Perches675418d2012-05-16 19:28:38 +0000969 ND_PRINTK(1, err, "RS: can't find in6 device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return;
971 }
972
973 /* Don't accept RS if we're not in router mode */
974 if (!idev->cnf.forwarding)
975 goto out;
976
977 /*
978 * Don't update NCE if src = ::;
979 * this implies that the source node has no ip address assigned yet.
980 */
981 if (ipv6_addr_any(saddr))
982 goto out;
983
984 /* Parse ND options */
985 if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000986 ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 goto out;
988 }
989
990 if (ndopts.nd_opts_src_lladdr) {
991 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
992 skb->dev);
993 if (!lladdr)
994 goto out;
995 }
996
997 neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
998 if (neigh) {
999 neigh_update(neigh, lladdr, NUD_STALE,
1000 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1001 NEIGH_UPDATE_F_OVERRIDE|
1002 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
1003 neigh_release(neigh);
1004 }
1005out:
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001006 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007}
1008
Pierre Ynard31910572007-10-10 21:22:05 -07001009static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
1010{
1011 struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
1012 struct sk_buff *skb;
1013 struct nlmsghdr *nlh;
1014 struct nduseroptmsg *ndmsg;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001015 struct net *net = dev_net(ra->dev);
Pierre Ynard31910572007-10-10 21:22:05 -07001016 int err;
1017 int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
1018 + (opt->nd_opt_len << 3));
1019 size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
1020
1021 skb = nlmsg_new(msg_size, GFP_ATOMIC);
1022 if (skb == NULL) {
1023 err = -ENOBUFS;
1024 goto errout;
1025 }
1026
1027 nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
1028 if (nlh == NULL) {
1029 goto nla_put_failure;
1030 }
1031
1032 ndmsg = nlmsg_data(nlh);
1033 ndmsg->nduseropt_family = AF_INET6;
Pierre Ynarddbb2ed22007-11-12 17:58:35 -08001034 ndmsg->nduseropt_ifindex = ra->dev->ifindex;
Pierre Ynard31910572007-10-10 21:22:05 -07001035 ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
1036 ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
1037 ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
1038
1039 memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
1040
David S. Millerc78679e2012-04-01 20:27:33 -04001041 if (nla_put(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
1042 &ipv6_hdr(ra)->saddr))
1043 goto nla_put_failure;
Pierre Ynard31910572007-10-10 21:22:05 -07001044 nlmsg_end(skb, nlh);
1045
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08001046 rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
Pierre Ynard31910572007-10-10 21:22:05 -07001047 return;
1048
1049nla_put_failure:
1050 nlmsg_free(skb);
1051 err = -EMSGSIZE;
1052errout:
Daniel Lezcanoa18bc692008-03-07 11:14:49 -08001053 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
Pierre Ynard31910572007-10-10 21:22:05 -07001054}
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056static void ndisc_router_discovery(struct sk_buff *skb)
1057{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001058 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct neighbour *neigh = NULL;
1060 struct inet6_dev *in6_dev;
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001061 struct rt6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 int lifetime;
1063 struct ndisc_options ndopts;
1064 int optlen;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001065 unsigned int pref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 __u8 * opt = (__u8 *)(ra_msg + 1);
1068
Simon Horman29a3cad2013-05-28 20:34:26 +00001069 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1070 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);
Simon Horman29a3cad2013-05-28 20:34:26 +00001347 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001348 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
Duan Jiongc92a59e2013-08-22 12:07:35 +08001369 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001370 ip6_redirect_no_header(skb, dev_net(skb->dev),
1371 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001372 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001373 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001374
1375 hdr = (u8 *)ndopts.nd_opts_rh;
1376 hdr += 8;
1377 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1378 return;
1379
David S. Millerb94f1c02012-07-12 00:33:37 -07001380 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381}
1382
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001383static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1384 struct sk_buff *orig_skb,
1385 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001386{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001387 u8 *opt = skb_put(skb, rd_len);
1388
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001389 memset(opt, 0, 8);
1390 *(opt++) = ND_OPT_REDIRECT_HDR;
1391 *(opt++) = (rd_len >> 3);
1392 opt += 6;
1393
1394 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001395}
1396
David S. Miller49919692012-01-27 15:30:48 -08001397void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001399 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001400 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001401 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001402 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001403 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001405 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 struct rt6_info *rt;
1408 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001409 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001412 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Neil Horman95c385b2007-04-25 17:08:10 -07001414 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001415 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1416 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001417 return;
1418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001420 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001421 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001422 ND_PRINTK(2, warn,
1423 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001424 return;
1425 }
1426
David S. Miller4c9483b2011-03-12 16:22:43 -05001427 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001428 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
David S. Miller4c9483b2011-03-12 16:22:43 -05001430 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001431 if (dst->error) {
1432 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001434 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001435 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001436 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
1439 rt = (struct rt6_info *) dst;
1440
1441 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001442 ND_PRINTK(2, warn,
1443 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001444 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001446 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1447 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1448 if (peer)
1449 inet_putpeer(peer);
1450 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001451 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001454 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1455 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001456 ND_PRINTK(2, warn,
1457 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001458 goto release;
1459 }
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 read_lock_bh(&neigh->lock);
1462 if (neigh->nud_state & NUD_VALID) {
1463 memcpy(ha_buf, neigh->ha, dev->addr_len);
1464 read_unlock_bh(&neigh->lock);
1465 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001466 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 } else
1468 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001469
1470 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 }
1472
1473 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001474 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1475 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001477 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001479 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001480 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001481 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001483 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1484 *msg = (struct rd_msg) {
1485 .icmph = {
1486 .icmp6_type = NDISC_REDIRECT,
1487 },
1488 .target = *target,
1489 .dest = ipv6_hdr(skb)->daddr,
1490 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 /*
1493 * include target_address option
1494 */
1495
1496 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001497 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 /*
1500 * build redirect option and copy skb over to the new packet.
1501 */
1502
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001503 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001504 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Eric Dumazetadf30902009-06-02 05:19:30 +00001506 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001507 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001508 return;
1509
1510release:
1511 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512}
1513
1514static void pndisc_redo(struct sk_buff *skb)
1515{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001516 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 kfree_skb(skb);
1518}
1519
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001520static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1521{
1522 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1523
1524 if (!idev)
1525 return true;
1526 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1527 idev->cnf.suppress_frag_ndisc) {
1528 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1529 return true;
1530 }
1531 return false;
1532}
1533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534int ndisc_rcv(struct sk_buff *skb)
1535{
1536 struct nd_msg *msg;
1537
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001538 if (ndisc_suppress_frag_ndisc(skb))
1539 return 0;
1540
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001541 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 return 0;
1543
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001544 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001546 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001548 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001549 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1550 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return 0;
1552 }
1553
1554 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001555 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1556 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 return 0;
1558 }
1559
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001560 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 switch (msg->icmph.icmp6_type) {
1563 case NDISC_NEIGHBOUR_SOLICITATION:
1564 ndisc_recv_ns(skb);
1565 break;
1566
1567 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1568 ndisc_recv_na(skb);
1569 break;
1570
1571 case NDISC_ROUTER_SOLICITATION:
1572 ndisc_recv_rs(skb);
1573 break;
1574
1575 case NDISC_ROUTER_ADVERTISEMENT:
1576 ndisc_router_discovery(skb);
1577 break;
1578
1579 case NDISC_REDIRECT:
1580 ndisc_redirect_rcv(skb);
1581 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 return 0;
1585}
1586
1587static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1588{
Jiri Pirko351638e2013-05-28 01:30:21 +00001589 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001590 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001591 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 switch (event) {
1594 case NETDEV_CHANGEADDR:
1595 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001596 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001597 idev = in6_dev_get(dev);
1598 if (!idev)
1599 break;
1600 if (idev->cnf.ndisc_notify)
1601 ndisc_send_unsol_na(dev);
1602 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 break;
1604 case NETDEV_DOWN:
1605 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001606 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001608 case NETDEV_NOTIFY_PEERS:
1609 ndisc_send_unsol_na(dev);
1610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 default:
1612 break;
1613 }
1614
1615 return NOTIFY_DONE;
1616}
1617
1618static struct notifier_block ndisc_netdev_notifier = {
1619 .notifier_call = ndisc_netdev_event,
1620};
1621
1622#ifdef CONFIG_SYSCTL
1623static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1624 const char *func, const char *dev_name)
1625{
1626 static char warncomm[TASK_COMM_LEN];
1627 static int warned;
1628 if (strcmp(warncomm, current->comm) && warned < 5) {
1629 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001630 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 -07001631 warncomm, func,
1632 dev_name, ctl->procname,
1633 dev_name, ctl->procname);
1634 warned++;
1635 }
1636}
1637
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001638int 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 -07001639{
1640 struct net_device *dev = ctl->extra1;
1641 struct inet6_dev *idev;
1642 int ret;
1643
Eric W. Biedermand12af672007-10-18 03:05:25 -07001644 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1645 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1647
Eric W. Biedermand12af672007-10-18 03:05:25 -07001648 if (strcmp(ctl->procname, "retrans_time") == 0)
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001649 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001650
1651 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 ret = proc_dointvec_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001653 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001654
1655 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001656 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 ret = proc_dointvec_ms_jiffies(ctl, write,
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001658 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001659 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Eric W. Biedermand12af672007-10-18 03:05:25 -07001663 if (ctl->data == &idev->nd_parms->base_reachable_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
1665 idev->tstamp = jiffies;
1666 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1667 in6_dev_put(idev);
1668 }
1669 return ret;
1670}
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673#endif
1674
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001675static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676{
1677 struct ipv6_pinfo *np;
1678 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001679 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001681 err = inet_ctl_sock_create(&sk, PF_INET6,
1682 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001684 ND_PRINTK(0, err,
1685 "NDISC: Failed to initialize the control socket (err %d)\n",
1686 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return err;
1688 }
1689
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001690 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 np->hop_limit = 255;
1694 /* Do not loopback ndisc messages */
1695 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001697 return 0;
1698}
1699
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001700static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001701{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001702 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001703}
1704
1705static struct pernet_operations ndisc_net_ops = {
1706 .init = ndisc_net_init,
1707 .exit = ndisc_net_exit,
1708};
1709
1710int __init ndisc_init(void)
1711{
1712 int err;
1713
1714 err = register_pernet_subsys(&ndisc_net_ops);
1715 if (err)
1716 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001717 /*
1718 * Initialize the neighbour table
1719 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 neigh_table_init(&nd_tbl);
1721
1722#ifdef CONFIG_SYSCTL
Eric W. Biederman54716e32010-02-14 03:27:03 +00001723 err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6",
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001724 &ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001725 if (err)
1726 goto out_unregister_pernet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001728 err = register_netdevice_notifier(&ndisc_netdev_notifier);
1729 if (err)
1730 goto out_unregister_sysctl;
1731out:
1732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001734out_unregister_sysctl:
1735#ifdef CONFIG_SYSCTL
1736 neigh_sysctl_unregister(&nd_tbl.parms);
1737out_unregister_pernet:
1738#endif
1739 unregister_pernet_subsys(&ndisc_net_ops);
1740 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741}
1742
1743void ndisc_cleanup(void)
1744{
Dmitry Mishin36f73d02006-11-03 16:08:19 -08001745 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746#ifdef CONFIG_SYSCTL
1747 neigh_sysctl_unregister(&nd_tbl.parms);
1748#endif
1749 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001750 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751}