blob: ca8d4ea48a5d9fa641bf129a6fc5e3b428799fa4 [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,
Shan Weib6720832010-12-01 18:05:12 +0000128 .reachable_time = ND_REACHABLE_TIME,
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100129 .data = {
130 [NEIGH_VAR_MCAST_PROBES] = 3,
131 [NEIGH_VAR_UCAST_PROBES] = 3,
132 [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
133 [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
134 [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
135 [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
136 [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
137 [NEIGH_VAR_PROXY_QLEN] = 64,
138 [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
139 [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
140 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 },
142 .gc_interval = 30 * HZ,
143 .gc_thresh1 = 128,
144 .gc_thresh2 = 512,
145 .gc_thresh3 = 1024,
146};
147
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000148static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +0000150 int pad = ndisc_addr_option_pad(skb->dev->type);
151 int data_len = skb->dev->addr_len;
152 int space = ndisc_opt_addr_space(skb->dev);
153 u8 *opt = skb_put(skb, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 opt[0] = type;
156 opt[1] = space>>3;
157
158 memset(opt + 2, 0, pad);
159 opt += pad;
160 space -= pad;
161
162 memcpy(opt+2, data, data_len);
163 data_len += 2;
164 opt += data_len;
165 if ((space -= data_len) > 0)
166 memset(opt, 0, space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
169static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
170 struct nd_opt_hdr *end)
171{
172 int type;
173 if (!cur || !end || cur >= end)
174 return NULL;
175 type = cur->nd_opt_type;
176 do {
177 cur = ((void *)cur) + (cur->nd_opt_len << 3);
178 } while(cur < end && cur->nd_opt_type != type);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000179 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
Pierre Ynard31910572007-10-10 21:22:05 -0700182static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
183{
Alexey I. Froloffe35f30c2012-04-06 05:50:58 +0000184 return opt->nd_opt_type == ND_OPT_RDNSS ||
185 opt->nd_opt_type == ND_OPT_DNSSL;
Pierre Ynard31910572007-10-10 21:22:05 -0700186}
187
188static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
189 struct nd_opt_hdr *end)
190{
191 if (!cur || !end || cur >= end)
192 return NULL;
193 do {
194 cur = ((void *)cur) + (cur->nd_opt_len << 3);
195 } while(cur < end && !ndisc_is_useropt(cur));
Eric Dumazeta02cec22010-09-22 20:43:57 +0000196 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
Pierre Ynard31910572007-10-10 21:22:05 -0700197}
198
David S. Miller30f2a5f2012-07-11 23:26:46 -0700199struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
200 struct ndisc_options *ndopts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
203
204 if (!nd_opt || opt_len < 0 || !ndopts)
205 return NULL;
206 memset(ndopts, 0, sizeof(*ndopts));
207 while (opt_len) {
208 int l;
209 if (opt_len < sizeof(struct nd_opt_hdr))
210 return NULL;
211 l = nd_opt->nd_opt_len << 3;
212 if (opt_len < l || l == 0)
213 return NULL;
214 switch (nd_opt->nd_opt_type) {
215 case ND_OPT_SOURCE_LL_ADDR:
216 case ND_OPT_TARGET_LL_ADDR:
217 case ND_OPT_MTU:
218 case ND_OPT_REDIRECT_HDR:
219 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
Joe Perches675418d2012-05-16 19:28:38 +0000220 ND_PRINTK(2, warn,
221 "%s: duplicated ND6 option found: type=%d\n",
222 __func__, nd_opt->nd_opt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 } else {
224 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
225 }
226 break;
227 case ND_OPT_PREFIX_INFO:
228 ndopts->nd_opts_pi_end = nd_opt;
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -0700229 if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
231 break;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800232#ifdef CONFIG_IPV6_ROUTE_INFO
233 case ND_OPT_ROUTE_INFO:
234 ndopts->nd_opts_ri_end = nd_opt;
235 if (!ndopts->nd_opts_ri)
236 ndopts->nd_opts_ri = nd_opt;
237 break;
238#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 default:
Pierre Ynard31910572007-10-10 21:22:05 -0700240 if (ndisc_is_useropt(nd_opt)) {
241 ndopts->nd_useropts_end = nd_opt;
242 if (!ndopts->nd_useropts)
243 ndopts->nd_useropts = nd_opt;
244 } else {
245 /*
246 * Unknown options must be silently ignored,
247 * to accommodate future extension to the
248 * protocol.
249 */
Joe Perches675418d2012-05-16 19:28:38 +0000250 ND_PRINTK(2, notice,
251 "%s: ignored unsupported option; type=%d, len=%d\n",
252 __func__,
253 nd_opt->nd_opt_type,
254 nd_opt->nd_opt_len);
Pierre Ynard31910572007-10-10 21:22:05 -0700255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
257 opt_len -= l;
258 nd_opt = ((void *)nd_opt) + l;
259 }
260 return ndopts;
261}
262
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000263int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 switch (dev->type) {
266 case ARPHRD_ETHER:
267 case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
268 case ARPHRD_FDDI:
269 ipv6_eth_mc_map(addr, buf);
270 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 case ARPHRD_ARCNET:
272 ipv6_arcnet_mc_map(addr, buf);
273 return 0;
274 case ARPHRD_INFINIBAND:
Rolf Manderscheida9e527e2007-12-10 13:38:41 -0700275 ipv6_ib_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
Timo Teräs93ca3bb2011-03-28 22:40:53 +0000277 case ARPHRD_IPGRE:
278 return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 default:
280 if (dir) {
281 memcpy(buf, dev->broadcast, dev->addr_len);
282 return 0;
283 }
284 }
285 return -EINVAL;
286}
287
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900288EXPORT_SYMBOL(ndisc_mc_map);
289
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000290static u32 ndisc_hash(const void *pkey,
291 const struct net_device *dev,
David S. Miller2c2aba62011-12-28 15:06:58 -0500292 __u32 *hash_rnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
David S. Miller2c2aba62011-12-28 15:06:58 -0500294 return ndisc_hashfn(pkey, dev, hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
297static int ndisc_constructor(struct neighbour *neigh)
298{
299 struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
300 struct net_device *dev = neigh->dev;
301 struct inet6_dev *in6_dev;
302 struct neigh_parms *parms;
Eric Dumazeta50feda2012-05-18 18:57:34 +0000303 bool is_multicast = ipv6_addr_is_multicast(addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 in6_dev = in6_dev_get(dev);
306 if (in6_dev == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return -EINVAL;
308 }
309
310 parms = in6_dev->nd_parms;
311 __neigh_parms_put(neigh->parms);
312 neigh->parms = neigh_parms_clone(parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700315 if (!dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 neigh->nud_state = NUD_NOARP;
317 neigh->ops = &ndisc_direct_ops;
David S. Miller8f40b162011-07-17 13:34:11 -0700318 neigh->output = neigh_direct_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 } else {
320 if (is_multicast) {
321 neigh->nud_state = NUD_NOARP;
322 ndisc_mc_map(addr, neigh->ha, dev, 1);
323 } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
324 neigh->nud_state = NUD_NOARP;
325 memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
326 if (dev->flags&IFF_LOOPBACK)
327 neigh->type = RTN_LOCAL;
328 } else if (dev->flags&IFF_POINTOPOINT) {
329 neigh->nud_state = NUD_NOARP;
330 memcpy(neigh->ha, dev->broadcast, dev->addr_len);
331 }
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700332 if (dev->header_ops->cache)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 neigh->ops = &ndisc_hh_ops;
334 else
335 neigh->ops = &ndisc_generic_ops;
336 if (neigh->nud_state&NUD_VALID)
337 neigh->output = neigh->ops->connected_output;
338 else
339 neigh->output = neigh->ops->output;
340 }
341 in6_dev_put(in6_dev);
342 return 0;
343}
344
345static int pndisc_constructor(struct pneigh_entry *n)
346{
347 struct in6_addr *addr = (struct in6_addr*)&n->key;
348 struct in6_addr maddr;
349 struct net_device *dev = n->dev;
350
351 if (dev == NULL || __in6_dev_get(dev) == NULL)
352 return -EINVAL;
353 addrconf_addr_solict_mult(addr, &maddr);
354 ipv6_dev_mc_inc(dev, &maddr);
355 return 0;
356}
357
358static void pndisc_destructor(struct pneigh_entry *n)
359{
360 struct in6_addr *addr = (struct in6_addr*)&n->key;
361 struct in6_addr maddr;
362 struct net_device *dev = n->dev;
363
364 if (dev == NULL || __in6_dev_get(dev) == NULL)
365 return;
366 addrconf_addr_solict_mult(addr, &maddr);
367 ipv6_dev_mc_dec(dev, &maddr);
368}
369
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000370static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
371 int len)
372{
373 int hlen = LL_RESERVED_SPACE(dev);
374 int tlen = dev->needed_tailroom;
375 struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
376 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000377
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200378 skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000379 if (!skb) {
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200380 ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
381 __func__);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000382 return NULL;
383 }
384
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000385 skb->protocol = htons(ETH_P_IPV6);
386 skb->dev = dev;
387
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000388 skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki / 吉藤英明5135e632013-01-21 06:48:44 +0000389 skb_reset_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000390
Thomas Graf25a6e6b2013-09-03 13:37:01 +0200391 /* Manually assign socket ownership as we avoid calling
392 * sock_alloc_send_pskb() to bypass wmem buffer limits
393 */
394 skb_set_owner_w(skb, sk);
395
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +0000396 return skb;
397}
398
YOSHIFUJI Hideaki / 吉藤英明f382d032013-01-21 06:48:29 +0000399static void ip6_nd_hdr(struct sk_buff *skb,
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000400 const struct in6_addr *saddr,
401 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000402 int hop_limit, int len)
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000403{
404 struct ipv6hdr *hdr;
405
YOSHIFUJI Hideaki / 吉藤英明527a1502013-01-21 06:48:39 +0000406 skb_push(skb, sizeof(*hdr));
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000407 skb_reset_network_header(skb);
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000408 hdr = ipv6_hdr(skb);
409
410 ip6_flow_hdr(hdr, 0, 0);
411
412 hdr->payload_len = htons(len);
YOSHIFUJI Hideaki / 吉藤英明c8d6c382013-01-21 06:48:24 +0000413 hdr->nexthdr = IPPROTO_ICMPV6;
414 hdr->hop_limit = hop_limit;
YOSHIFUJI Hideaki / 吉藤英明2576f172013-01-21 06:48:19 +0000415
416 hdr->saddr = *saddr;
417 hdr->daddr = *daddr;
418}
419
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000420static void ndisc_send_skb(struct sk_buff *skb,
YOSHIFUJI Hideakifd0ea7d2012-12-13 02:40:26 +0900421 const struct in6_addr *daddr,
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000422 const struct in6_addr *saddr)
Brian Haley305d5522008-11-04 17:51:14 -0800423{
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000424 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki / 吉藤英明af9a9972013-01-21 06:48:34 +0000425 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000426 struct sock *sk = net->ipv6.ndisc_sk;
Brian Haley305d5522008-11-04 17:51:14 -0800427 struct inet6_dev *idev;
428 int err;
YOSHIFUJI Hideaki / 吉藤英明aa4bdd42013-01-21 06:48:58 +0000429 struct icmp6hdr *icmp6h = icmp6_hdr(skb);
Brian Haley305d5522008-11-04 17:51:14 -0800430 u8 type;
431
432 type = icmp6h->icmp6_type;
433
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000434 if (!dst) {
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000435 struct flowi6 fl6;
Brian Haley305d5522008-11-04 17:51:14 -0800436
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +0000437 icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
438 dst = icmp6_dst_alloc(skb->dev, &fl6);
439 if (IS_ERR(dst)) {
440 kfree_skb(skb);
441 return;
442 }
443
444 skb_dst_set(skb, dst);
445 }
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900446
YOSHIFUJI Hideaki / 吉藤英明7b3d9b02013-01-21 06:49:08 +0000447 icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
448 IPPROTO_ICMPV6,
449 csum_partial(icmp6h,
450 skb->len, 0));
451
452 ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
453
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000454 rcu_read_lock();
455 idev = __in6_dev_get(dst->dev);
Neil Hormanedf391f2009-04-27 02:45:02 -0700456 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900457
Jan Engelhardtb2e0b382010-03-23 04:09:07 +0100458 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Patrick McHardy6e23ae22007-11-19 18:53:30 -0800459 dst_output);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900460 if (!err) {
Denis V. Lunev5c5d2442008-10-08 10:33:50 -0700461 ICMP6MSGOUT_INC_STATS(net, idev, type);
Denis V. Luneva862f6a2008-10-08 10:33:06 -0700462 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900463 }
464
Eric Dumazetcfdf7642011-07-27 21:13:03 +0000465 rcu_read_unlock();
YOSHIFUJI Hideakie1ec7842007-04-24 20:44:52 +0900466}
467
Cong Wangf564f452013-08-31 13:44:36 +0800468void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
469 const struct in6_addr *daddr,
470 const struct in6_addr *solicited_addr,
471 bool router, bool solicited, bool override, bool inc_opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000473 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct in6_addr tmpaddr;
475 struct inet6_ifaddr *ifp;
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900476 const struct in6_addr *src_addr;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000477 struct nd_msg *msg;
478 int optlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 /* for anycast or proxy, solicited_addr != src_addr */
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900481 ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900482 if (ifp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 src_addr = solicited_addr;
Neil Horman95c385b2007-04-25 17:08:10 -0700484 if (ifp->flags & IFA_F_OPTIMISTIC)
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300485 override = false;
stephen hemminger9f888162010-06-21 11:00:13 +0000486 inc_opt |= ifp->idev->cnf.force_tllao;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 in6_ifa_put(ifp);
488 } else {
Brian Haley191cd582008-08-14 15:33:21 -0700489 if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900490 inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
YOSHIFUJI Hideaki7cbca672008-03-25 09:37:42 +0900491 &tmpaddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return;
493 src_addr = &tmpaddr;
494 }
495
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000496 if (!dev->addr_len)
497 inc_opt = 0;
498 if (inc_opt)
499 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000501 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000502 if (!skb)
503 return;
504
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000505 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
506 *msg = (struct nd_msg) {
507 .icmph = {
508 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
509 .icmp6_router = router,
510 .icmp6_solicited = solicited,
511 .icmp6_override = override,
512 },
513 .target = *solicited_addr,
514 };
515
516 if (inc_opt)
517 ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
518 dev->dev_addr);
519
520
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000521 ndisc_send_skb(skb, daddr, src_addr);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900522}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000524static void ndisc_send_unsol_na(struct net_device *dev)
525{
526 struct inet6_dev *idev;
527 struct inet6_ifaddr *ifa;
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000528
529 idev = in6_dev_get(dev);
530 if (!idev)
531 return;
532
533 read_lock_bh(&idev->lock);
534 list_for_each_entry(ifa, &idev->addr_list, if_list) {
YOSHIFUJI Hideaki / 吉藤英明9fafd652012-11-12 07:50:17 +0000535 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
Ben Hutchingsf47b9462011-04-15 13:46:02 +0000536 /*router=*/ !!idev->cnf.forwarding,
537 /*solicited=*/ false, /*override=*/ true,
538 /*inc_opt=*/ true);
539 }
540 read_unlock_bh(&idev->lock);
541
542 in6_dev_put(idev);
543}
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900546 const struct in6_addr *solicit,
547 const struct in6_addr *daddr, const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000549 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 struct in6_addr addr_buf;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000551 int inc_opt = dev->addr_len;
552 int optlen = 0;
553 struct nd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (saddr == NULL) {
Neil Horman95c385b2007-04-25 17:08:10 -0700556 if (ipv6_get_lladdr(dev, &addr_buf,
557 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 return;
559 saddr = &addr_buf;
560 }
561
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000562 if (ipv6_addr_any(saddr))
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300563 inc_opt = false;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000564 if (inc_opt)
565 optlen += ndisc_opt_addr_space(dev);
566
567 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000568 if (!skb)
569 return;
570
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000571 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
572 *msg = (struct nd_msg) {
573 .icmph = {
574 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
575 },
576 .target = *solicit,
577 };
578
579 if (inc_opt)
580 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
581 dev->dev_addr);
582
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000583 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900586void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
587 const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000589 struct sk_buff *skb;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000590 struct rs_msg *msg;
Neil Horman95c385b2007-04-25 17:08:10 -0700591 int send_sllao = dev->addr_len;
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000592 int optlen = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700593
594#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
595 /*
596 * According to section 2.2 of RFC 4429, we must not
597 * send router solicitations with a sllao from
598 * optimistic addresses, but we may send the solicitation
599 * if we don't include the sllao. So here we check
600 * if our address is optimistic, and if so, we
Joe Perchesbea85192007-12-20 14:01:35 -0800601 * suppress the inclusion of the sllao.
Neil Horman95c385b2007-04-25 17:08:10 -0700602 */
603 if (send_sllao) {
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900604 struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
Daniel Lezcano1cab3da2008-01-10 22:44:09 -0800605 dev, 1);
Neil Horman95c385b2007-04-25 17:08:10 -0700606 if (ifp) {
607 if (ifp->flags & IFA_F_OPTIMISTIC) {
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900608 send_sllao = 0;
Neil Horman95c385b2007-04-25 17:08:10 -0700609 }
YOSHIFUJI Hideakica043562007-02-28 23:13:20 +0900610 in6_ifa_put(ifp);
Neil Horman95c385b2007-04-25 17:08:10 -0700611 } else {
612 send_sllao = 0;
613 }
614 }
615#endif
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000616 if (send_sllao)
617 optlen += ndisc_opt_addr_space(dev);
618
619 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000620 if (!skb)
621 return;
622
YOSHIFUJI Hideaki / 吉藤英明1cb3fe52013-01-21 06:49:17 +0000623 msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
624 *msg = (struct rs_msg) {
625 .icmph = {
626 .icmp6_type = NDISC_ROUTER_SOLICITATION,
627 },
628 };
629
630 if (send_sllao)
631 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
632 dev->dev_addr);
633
YOSHIFUJI Hideaki / 吉藤英明b44b5f42013-01-21 06:49:13 +0000634 ndisc_send_skb(skb, daddr, saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635}
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
639{
640 /*
641 * "The sender MUST return an ICMP
642 * destination unreachable"
643 */
644 dst_link_failure(skb);
645 kfree_skb(skb);
646}
647
648/* Called with locked neigh: either read or both */
649
650static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
651{
652 struct in6_addr *saddr = NULL;
653 struct in6_addr mcaddr;
654 struct net_device *dev = neigh->dev;
655 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
656 int probes = atomic_read(&neigh->probes);
657
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900658 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700659 saddr = &ipv6_hdr(skb)->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100661 if ((probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (!(neigh->nud_state & NUD_VALID)) {
Joe Perches675418d2012-05-16 19:28:38 +0000663 ND_PRINTK(1, dbg,
664 "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
665 __func__, target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
667 ndisc_send_ns(dev, neigh, target, target, saddr);
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100668 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 neigh_app_ns(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 } else {
671 addrconf_addr_solict_mult(target, &mcaddr);
672 ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
673 }
674}
675
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900676static int pndisc_is_router(const void *pkey,
677 struct net_device *dev)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700678{
679 struct pneigh_entry *n;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900680 int ret = -1;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700681
682 read_lock_bh(&nd_tbl.lock);
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900683 n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
684 if (n)
685 ret = !!(n->flags & NTF_ROUTER);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700686 read_unlock_bh(&nd_tbl.lock);
687
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900688 return ret;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700689}
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691static void ndisc_recv_ns(struct sk_buff *skb)
692{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700693 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000694 const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
695 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000697 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700698 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 struct ndisc_options ndopts;
700 struct net_device *dev = skb->dev;
701 struct inet6_ifaddr *ifp;
702 struct inet6_dev *idev = NULL;
703 struct neighbour *neigh;
704 int dad = ipv6_addr_any(saddr);
Eric Dumazeta50feda2012-05-18 18:57:34 +0000705 bool inc;
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900706 int is_router = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
YOSHIFUJI Hideaki / 吉藤英明115b0aa2013-01-18 02:05:03 +0000708 if (skb->len < sizeof(struct nd_msg)) {
709 ND_PRINTK(2, warn, "NS: packet too short\n");
710 return;
711 }
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000714 ND_PRINTK(2, warn, "NS: multicast target address\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return;
716 }
717
718 /*
719 * RFC2461 7.1.1:
720 * DAD has to be destined for solicited node multicast address.
721 */
YOSHIFUJI Hideaki / 吉藤英明ca97a642013-01-20 07:39:00 +0000722 if (dad && !ipv6_addr_is_solict_mult(daddr)) {
Joe Perches675418d2012-05-16 19:28:38 +0000723 ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return;
725 }
726
727 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000728 ND_PRINTK(2, warn, "NS: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 return;
730 }
731
732 if (ndopts.nd_opts_src_lladdr) {
733 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
734 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000735 ND_PRINTK(2, warn,
736 "NS: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return;
738 }
739
740 /* RFC2461 7.1.1:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900741 * If the IP source address is the unspecified address,
742 * there MUST NOT be source link-layer address option
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 * in the message.
744 */
745 if (dad) {
Joe Perches675418d2012-05-16 19:28:38 +0000746 ND_PRINTK(2, warn,
747 "NS: bad DAD packet (link-layer address option)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return;
749 }
750 }
751
752 inc = ipv6_addr_is_multicast(daddr);
753
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900754 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800755 if (ifp) {
Neil Horman95c385b2007-04-25 17:08:10 -0700756
757 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
758 if (dad) {
Neil Horman95c385b2007-04-25 17:08:10 -0700759 /*
760 * We are colliding with another node
761 * who is doing DAD
762 * so fail our DAD process
763 */
764 addrconf_dad_failure(ifp);
Denis V. Lunev9e3be4b2007-09-11 11:04:49 +0200765 return;
Neil Horman95c385b2007-04-25 17:08:10 -0700766 } else {
767 /*
768 * This is not a dad solicitation.
769 * If we are an optimistic node,
770 * we should respond.
771 * Otherwise, we should ignore it.
772 */
773 if (!(ifp->flags & IFA_F_OPTIMISTIC))
774 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
777
778 idev = ifp->idev;
779 } else {
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700780 struct net *net = dev_net(dev);
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 idev = in6_dev_get(dev);
783 if (!idev) {
784 /* XXX: count this drop? */
785 return;
786 }
787
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700788 if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900789 (idev->cnf.forwarding &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700790 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900791 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
Patrick McHardya61bbcf2005-08-14 17:24:31 -0700792 if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 skb->pkt_type != PACKET_HOST &&
Daniel Balutaf2f79cc2013-07-13 11:26:51 +0300794 inc &&
Jiri Pirko1f9248e52013-12-07 19:26:53 +0100795 NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 /*
797 * for anycast or proxy,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900798 * sender should delay its response
799 * by a random time between 0 and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 * MAX_ANYCAST_DELAY_TIME seconds.
801 * (RFC2461) -- yoshfuji
802 */
803 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
804 if (n)
805 pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
806 goto out;
807 }
808 } else
809 goto out;
810 }
811
YOSHIFUJI Hideaki0736ffc2008-03-28 13:37:58 +0900812 if (is_router < 0)
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000813 is_router = idev->cnf.forwarding;
Ville Nuorvala62dd9312006-09-22 14:43:19 -0700814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 if (dad) {
YOSHIFUJI Hideakif3ee4012008-04-10 15:42:11 +0900816 ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000817 !!is_router, false, (ifp != NULL), true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 goto out;
819 }
820
821 if (inc)
822 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
823 else
824 NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
825
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900826 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 * update / create cache entry
828 * for the source address
829 */
830 neigh = __neigh_lookup(&nd_tbl, saddr, dev,
831 !inc || lladdr || !dev->addr_len);
832 if (neigh)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900833 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 NEIGH_UPDATE_F_WEAK_OVERRIDE|
835 NEIGH_UPDATE_F_OVERRIDE);
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700836 if (neigh || !dev->header_ops) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 ndisc_send_na(dev, neigh, saddr, &msg->target,
YOSHIFUJI Hideaki / 吉藤英明fb568632013-01-20 07:39:18 +0000838 !!is_router,
839 true, (ifp != NULL && inc), inc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (neigh)
841 neigh_release(neigh);
842 }
843
844out:
845 if (ifp)
846 in6_ifa_put(ifp);
847 else
848 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
850
851static void ndisc_recv_na(struct sk_buff *skb)
852{
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -0700853 struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Duan Jiongbe7a0102014-05-15 15:56:14 +0800854 struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000855 const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 u8 *lladdr = NULL;
Simon Horman29a3cad2013-05-28 20:34:26 +0000857 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700858 offsetof(struct nd_msg, opt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 struct ndisc_options ndopts;
860 struct net_device *dev = skb->dev;
861 struct inet6_ifaddr *ifp;
862 struct neighbour *neigh;
863
864 if (skb->len < sizeof(struct nd_msg)) {
Joe Perches675418d2012-05-16 19:28:38 +0000865 ND_PRINTK(2, warn, "NA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return;
867 }
868
869 if (ipv6_addr_is_multicast(&msg->target)) {
Joe Perches675418d2012-05-16 19:28:38 +0000870 ND_PRINTK(2, warn, "NA: target address is multicast\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return;
872 }
873
874 if (ipv6_addr_is_multicast(daddr) &&
875 msg->icmph.icmp6_solicited) {
Joe Perches675418d2012-05-16 19:28:38 +0000876 ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 return;
878 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +0000881 ND_PRINTK(2, warn, "NS: invalid ND option\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return;
883 }
884 if (ndopts.nd_opts_tgt_lladdr) {
885 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
886 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +0000887 ND_PRINTK(2, warn,
888 "NA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return;
890 }
891 }
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900892 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
Daniel Lezcanoa18bc692008-03-07 11:14:49 -0800893 if (ifp) {
Daniel Walterbd015922011-04-13 21:09:25 +0000894 if (skb->pkt_type != PACKET_LOOPBACK
895 && (ifp->flags & IFA_F_TENTATIVE)) {
896 addrconf_dad_failure(ifp);
897 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 /* What should we make now? The advertisement
900 is invalid, but ndisc specs say nothing
901 about it. It could be misconfiguration, or
902 an smart proxy agent tries to help us :-)
Jan Sembera24fc7b82008-12-09 15:48:32 -0800903
904 We should not print the error if NA has been
905 received from loopback - it is just our own
906 unsolicited advertisement.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 */
Jan Sembera24fc7b82008-12-09 15:48:32 -0800908 if (skb->pkt_type != PACKET_LOOPBACK)
Joe Perches675418d2012-05-16 19:28:38 +0000909 ND_PRINTK(1, warn,
910 "NA: someone advertises our address %pI6 on %s!\n",
911 &ifp->addr, ifp->idev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 in6_ifa_put(ifp);
913 return;
914 }
915 neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
916
917 if (neigh) {
918 u8 old_flags = neigh->flags;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700919 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 if (neigh->nud_state & NUD_FAILED)
922 goto out;
923
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700924 /*
925 * Don't update the neighbor cache entry on a proxy NA from
926 * ourselves because either the proxied node is off link or it
927 * has already sent a NA to us.
928 */
929 if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700930 net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
931 pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
Nicolas Dichtelb20b6d92012-11-07 05:05:38 +0000932 /* XXX: idev->cnf.proxy_ndp */
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700933 goto out;
YOSHIFUJI Hideakifbea49e2006-09-22 14:43:49 -0700934 }
Ville Nuorvala5f3e6e92006-09-22 14:42:46 -0700935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 neigh_update(neigh, lladdr,
937 msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
938 NEIGH_UPDATE_F_WEAK_OVERRIDE|
939 (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
940 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
941 (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
942
943 if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
944 /*
945 * Change: router to host
946 */
Duan Jiongbe7a0102014-05-15 15:56:14 +0800947 rt6_clean_tohost(dev_net(dev), saddr);
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
Simon Horman29a3cad2013-05-28 20:34:26 +00001070 optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
1071 sizeof(struct ra_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001073 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001074 ND_PRINTK(2, warn, "RA: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 return;
1076 }
1077 if (optlen < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001078 ND_PRINTK(2, warn, "RA: packet too short\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return;
1080 }
1081
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001082#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001083 if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
Joe Perches675418d2012-05-16 19:28:38 +00001084 ND_PRINTK(2, warn, "RA: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001085 return;
1086 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001087#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 /*
1090 * set the RA_RECV flag in the interface
1091 */
1092
Eric Dumazetcfdf7642011-07-27 21:13:03 +00001093 in6_dev = __in6_dev_get(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 if (in6_dev == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001095 ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n",
1096 skb->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return;
1098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
Joe Perches675418d2012-05-16 19:28:38 +00001101 ND_PRINTK(2, warn, "RA: invalid ND options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return;
1103 }
1104
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001105 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001106 goto skip_linkparms;
1107
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001108#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001109 /* skip link-specific parameters from interior routers */
1110 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1111 goto skip_linkparms;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001112#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (in6_dev->if_flags & IF_RS_SENT) {
1115 /*
1116 * flag that an RA was received after an RS was sent
1117 * out on this interface.
1118 */
1119 in6_dev->if_flags |= IF_RA_RCVD;
1120 }
1121
1122 /*
1123 * Remember the managed/otherconf flags from most recently
1124 * received RA message (RFC 2462) -- yoshfuji
1125 */
1126 in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
1127 IF_RA_OTHERCONF)) |
1128 (ra_msg->icmph.icmp6_addrconf_managed ?
1129 IF_RA_MANAGED : 0) |
1130 (ra_msg->icmph.icmp6_addrconf_other ?
1131 IF_RA_OTHERCONF : 0);
1132
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001133 if (!in6_dev->cnf.accept_ra_defrtr)
1134 goto skip_defrtr;
1135
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001136 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1137 goto skip_defrtr;
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1140
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001141#ifdef CONFIG_IPV6_ROUTER_PREF
1142 pref = ra_msg->icmph.icmp6_router_pref;
1143 /* 10b is handled as if it were 00b (medium) */
YOSHIFUJI Hideaki930d6ff2006-03-20 17:05:30 -08001144 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
YOSHIFUJI Hideaki6d5b78c2007-06-22 16:07:04 -07001145 !in6_dev->cnf.accept_ra_rtr_pref)
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001146 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1147#endif
1148
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001149 rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
David S. Millereb857182012-01-27 15:07:56 -08001151 if (rt) {
1152 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
1153 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001154 ND_PRINTK(0, err,
1155 "RA: %s got default router without neighbour\n",
1156 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001157 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001158 return;
1159 }
1160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (rt && lifetime == 0) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001162 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 rt = NULL;
1164 }
1165
1166 if (rt == NULL && lifetime) {
Joe Perches675418d2012-05-16 19:28:38 +00001167 ND_PRINTK(3, dbg, "RA: adding default router\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001169 rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (rt == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001171 ND_PRINTK(0, err,
1172 "RA: %s failed to add default route\n",
1173 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 return;
1175 }
1176
David S. Millereb857182012-01-27 15:07:56 -08001177 neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (neigh == NULL) {
Joe Perches675418d2012-05-16 19:28:38 +00001179 ND_PRINTK(0, err,
1180 "RA: %s got default router without neighbour\n",
1181 __func__);
Amerigo Wang94e187c2012-10-29 00:13:19 +00001182 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return;
1184 }
1185 neigh->flags |= NTF_ROUTER;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001186 } else if (rt) {
Pedro Ribeiro22441cf2008-10-15 15:47:49 -07001187 rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189
1190 if (rt)
Gao feng1716a962012-04-06 00:13:10 +00001191 rt6_set_expires(rt, jiffies + (HZ * lifetime));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 if (ra_msg->icmph.icmp6_hop_limit) {
1193 in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
1194 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001195 dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
1196 ra_msg->icmph.icmp6_hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
1198
YOSHIFUJI Hideaki65f5c7c2006-03-20 16:55:08 -08001199skip_defrtr:
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 /*
1202 * Update Reachable Time and Retrans Timer
1203 */
1204
1205 if (in6_dev->nd_parms) {
1206 unsigned long rtime = ntohl(ra_msg->retrans_timer);
1207
1208 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
1209 rtime = (rtime*HZ)/1000;
1210 if (rtime < HZ/10)
1211 rtime = HZ/10;
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001212 NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 in6_dev->tstamp = jiffies;
1214 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1215 }
1216
1217 rtime = ntohl(ra_msg->reachable_time);
1218 if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
1219 rtime = (rtime*HZ)/1000;
1220
1221 if (rtime < HZ/10)
1222 rtime = HZ/10;
1223
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001224 if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
1225 NEIGH_VAR_SET(in6_dev->nd_parms,
1226 BASE_REACHABLE_TIME, rtime);
1227 NEIGH_VAR_SET(in6_dev->nd_parms,
1228 GC_STALETIME, 3 * rtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
1230 in6_dev->tstamp = jiffies;
1231 inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
1232 }
1233 }
1234 }
1235
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001236skip_linkparms:
1237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 /*
1239 * Process options.
1240 */
1241
1242 if (!neigh)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001243 neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 skb->dev, 1);
1245 if (neigh) {
1246 u8 *lladdr = NULL;
1247 if (ndopts.nd_opts_src_lladdr) {
1248 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
1249 skb->dev);
1250 if (!lladdr) {
Joe Perches675418d2012-05-16 19:28:38 +00001251 ND_PRINTK(2, warn,
1252 "RA: invalid link-layer address length\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 goto out;
1254 }
1255 }
1256 neigh_update(neigh, lladdr, NUD_STALE,
1257 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1258 NEIGH_UPDATE_F_OVERRIDE|
1259 NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1260 NEIGH_UPDATE_F_ISROUTER);
1261 }
1262
Shmulik Ladkaniaeaf6e92012-11-30 10:25:59 +00001263 if (!ipv6_accept_ra(in6_dev))
David Ward31ce8c72009-08-29 00:04:09 -07001264 goto out;
1265
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001266#ifdef CONFIG_IPV6_ROUTE_INFO
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001267 if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
1268 goto skip_routeinfo;
1269
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001270 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001271 struct nd_opt_hdr *p;
1272 for (p = ndopts.nd_opts_ri;
1273 p;
1274 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001275 struct route_info *ri = (struct route_info *)p;
1276#ifdef CONFIG_IPV6_NDISC_NODETYPE
1277 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
1278 ri->prefix_len == 0)
1279 continue;
1280#endif
Duan Jiong30e56912013-11-26 15:46:56 +08001281 if (ri->prefix_len == 0 &&
1282 !in6_dev->cnf.accept_ra_defrtr)
1283 continue;
YOSHIFUJI Hideaki6294e002008-03-15 23:56:52 -04001284 if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
YOSHIFUJI Hideaki09c884d2006-03-20 17:07:03 -08001285 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001286 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001287 &ipv6_hdr(skb)->saddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001288 }
1289 }
Andreas Hofmeister9f562202011-10-24 19:13:15 -04001290
1291skip_routeinfo:
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001292#endif
1293
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001294#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001295 /* skip link-specific ndopts from interior routers */
1296 if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
1297 goto out;
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001298#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001299
YOSHIFUJI Hideakic4fd30e2006-03-20 16:55:26 -08001300 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 struct nd_opt_hdr *p;
1302 for (p = ndopts.nd_opts_pi;
1303 p;
1304 p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
Neil Hormane6bff992012-01-04 10:49:15 +00001305 addrconf_prefix_rcv(skb->dev, (u8 *)p,
1306 (p->nd_opt_len) << 3,
1307 ndopts.nd_opts_src_lladdr != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 }
1309 }
1310
1311 if (ndopts.nd_opts_mtu) {
Al Viroe69a4adc2006-11-14 20:56:00 -08001312 __be32 n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 u32 mtu;
1314
Al Viroe69a4adc2006-11-14 20:56:00 -08001315 memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
1316 mtu = ntohl(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
Joe Perches675418d2012-05-16 19:28:38 +00001319 ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 } else if (in6_dev->cnf.mtu6 != mtu) {
1321 in6_dev->cnf.mtu6 = mtu;
1322
1323 if (rt)
David S. Millerdefb3512010-12-08 21:16:57 -08001324 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 rt6_mtu_change(skb->dev, mtu);
1327 }
1328 }
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001329
Pierre Ynard31910572007-10-10 21:22:05 -07001330 if (ndopts.nd_useropts) {
YOSHIFUJI Hideaki61cf46ad2008-01-22 17:32:53 +09001331 struct nd_opt_hdr *p;
1332 for (p = ndopts.nd_useropts;
1333 p;
1334 p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
1335 ndisc_ra_useropt(skb, p);
Pierre Ynard31910572007-10-10 21:22:05 -07001336 }
1337 }
1338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
Joe Perches675418d2012-05-16 19:28:38 +00001340 ND_PRINTK(2, warn, "RA: invalid RA options\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
1342out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001343 ip6_rt_put(rt);
David S. Millereb857182012-01-27 15:07:56 -08001344 if (neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346}
1347
1348static void ndisc_redirect_rcv(struct sk_buff *skb)
1349{
Duan Jiong093d04d2012-12-14 02:59:59 +00001350 u8 *hdr;
1351 struct ndisc_options ndopts;
1352 struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
Simon Horman29a3cad2013-05-28 20:34:26 +00001353 u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
Duan Jiong093d04d2012-12-14 02:59:59 +00001354 offsetof(struct rd_msg, opt));
1355
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001356#ifdef CONFIG_IPV6_NDISC_NODETYPE
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001357 switch (skb->ndisc_nodetype) {
1358 case NDISC_NODETYPE_HOST:
1359 case NDISC_NODETYPE_NODEFAULT:
Joe Perches675418d2012-05-16 19:28:38 +00001360 ND_PRINTK(2, warn,
1361 "Redirect: from host or unauthorized router\n");
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001362 return;
1363 }
YOSHIFUJI Hideakide357cc2008-03-15 23:59:18 -04001364#endif
Templin, Fred Lfadf6bf2008-03-11 18:35:59 -04001365
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001366 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001367 ND_PRINTK(2, warn,
1368 "Redirect: source address is not link-local\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 return;
1370 }
1371
Duan Jiong093d04d2012-12-14 02:59:59 +00001372 if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
1373 return;
1374
Duan Jiongc92a59e2013-08-22 12:07:35 +08001375 if (!ndopts.nd_opts_rh) {
Duan Jiongb55b76b2013-09-04 19:44:21 +08001376 ip6_redirect_no_header(skb, dev_net(skb->dev),
1377 skb->dev->ifindex, 0);
Duan Jiong093d04d2012-12-14 02:59:59 +00001378 return;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001379 }
Duan Jiong093d04d2012-12-14 02:59:59 +00001380
1381 hdr = (u8 *)ndopts.nd_opts_rh;
1382 hdr += 8;
1383 if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
1384 return;
1385
David S. Millerb94f1c02012-07-12 00:33:37 -07001386 icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387}
1388
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001389static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
1390 struct sk_buff *orig_skb,
1391 int rd_len)
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001392{
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001393 u8 *opt = skb_put(skb, rd_len);
1394
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001395 memset(opt, 0, 8);
1396 *(opt++) = ND_OPT_REDIRECT_HDR;
1397 *(opt++) = (rd_len >> 3);
1398 opt += 6;
1399
1400 memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001401}
1402
David S. Miller49919692012-01-27 15:30:48 -08001403void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001405 struct net_device *dev = skb->dev;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001406 struct net *net = dev_net(dev);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001407 struct sock *sk = net->ipv6.ndisc_sk;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001408 int optlen = 0;
David S. Millerfbfe95a2012-06-08 23:24:18 -07001409 struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 struct sk_buff *buff;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001411 struct rd_msg *msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 struct in6_addr saddr_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 struct rt6_info *rt;
1414 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001415 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 int rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
David S. Miller1d861aa2012-07-10 03:58:16 -07001418 bool ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Neil Horman95c385b2007-04-25 17:08:10 -07001420 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
Joe Perches675418d2012-05-16 19:28:38 +00001421 ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n",
1422 dev->name);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001423 return;
1424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001426 if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
Brian Haleybf0b48d2007-10-08 00:12:05 -07001427 ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
Joe Perches675418d2012-05-16 19:28:38 +00001428 ND_PRINTK(2, warn,
1429 "Redirect: target address is not link-local unicast\n");
Li Yewang29556522007-01-30 14:33:20 -08001430 return;
1431 }
1432
David S. Miller4c9483b2011-03-12 16:22:43 -05001433 icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
YOSHIFUJI Hideaki95e41e92007-12-06 15:43:30 -08001434 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
David S. Miller4c9483b2011-03-12 16:22:43 -05001436 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001437 if (dst->error) {
1438 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 return;
RongQing.Li5095d642012-02-21 22:10:49 +00001440 }
David S. Miller4c9483b2011-03-12 16:22:43 -05001441 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
David S. Miller452edd52011-03-02 13:27:41 -08001442 if (IS_ERR(dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 rt = (struct rt6_info *) dst;
1446
1447 if (rt->rt6i_flags & RTF_GATEWAY) {
Joe Perches675418d2012-05-16 19:28:38 +00001448 ND_PRINTK(2, warn,
1449 "Redirect: destination is not a neighbour\n");
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001450 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 }
David S. Miller1d861aa2012-07-10 03:58:16 -07001452 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
1453 ret = inet_peer_xrlim_allow(peer, 1*HZ);
1454 if (peer)
1455 inet_putpeer(peer);
1456 if (!ret)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001457 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 if (dev->addr_len) {
David S. Miller49919692012-01-27 15:30:48 -08001460 struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
1461 if (!neigh) {
Joe Perches675418d2012-05-16 19:28:38 +00001462 ND_PRINTK(2, warn,
1463 "Redirect: no neigh for target address\n");
David S. Miller49919692012-01-27 15:30:48 -08001464 goto release;
1465 }
1466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 read_lock_bh(&neigh->lock);
1468 if (neigh->nud_state & NUD_VALID) {
1469 memcpy(ha_buf, neigh->ha, dev->addr_len);
1470 read_unlock_bh(&neigh->lock);
1471 ha = ha_buf;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001472 optlen += ndisc_opt_addr_space(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 } else
1474 read_unlock_bh(&neigh->lock);
David S. Miller49919692012-01-27 15:30:48 -08001475
1476 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478
1479 rd_len = min_t(unsigned int,
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001480 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1481 skb->len + 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 rd_len &= ~0x7;
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001483 optlen += rd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
YOSHIFUJI Hideaki / 吉藤英明2ce135762013-01-21 06:48:49 +00001485 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
YOSHIFUJI Hideaki / 吉藤英明de093342013-01-21 06:48:14 +00001486 if (!buff)
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001487 goto release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
YOSHIFUJI Hideaki / 吉藤英明4d5c1522013-01-21 06:49:25 +00001489 msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
1490 *msg = (struct rd_msg) {
1491 .icmph = {
1492 .icmp6_type = NDISC_REDIRECT,
1493 },
1494 .target = *target,
1495 .dest = ipv6_hdr(skb)->daddr,
1496 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 /*
1499 * include target_address option
1500 */
1501
1502 if (ha)
Matthias Schiffer33be0812013-05-31 03:27:55 +02001503 ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 /*
1506 * build redirect option and copy skb over to the new packet.
1507 */
1508
YOSHIFUJI Hideaki / 吉藤英明9c86daf2013-01-21 06:48:09 +00001509 if (rd_len)
YOSHIFUJI Hideaki / 吉藤英明5f5a0112013-01-21 06:48:53 +00001510 ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Eric Dumazetadf30902009-06-02 05:19:30 +00001512 skb_dst_set(buff, dst);
YOSHIFUJI Hideaki / 吉藤英明f4de84c2013-01-21 06:49:03 +00001513 ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
Ilpo Järvinend73f0802009-02-06 23:47:37 -08001514 return;
1515
1516release:
1517 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
1520static void pndisc_redo(struct sk_buff *skb)
1521{
YOSHIFUJI Hideaki140e26fc2005-10-05 12:11:41 -07001522 ndisc_recv_ns(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 kfree_skb(skb);
1524}
1525
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001526static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
1527{
1528 struct inet6_dev *idev = __in6_dev_get(skb->dev);
1529
1530 if (!idev)
1531 return true;
1532 if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1533 idev->cnf.suppress_frag_ndisc) {
1534 net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
1535 return true;
1536 }
1537 return false;
1538}
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540int ndisc_rcv(struct sk_buff *skb)
1541{
1542 struct nd_msg *msg;
1543
Hannes Frederic Sowab800c3b2013-08-27 01:36:51 +02001544 if (ndisc_suppress_frag_ndisc(skb))
1545 return 0;
1546
YOSHIFUJI Hideaki / 吉藤英明6bce6b42013-01-21 06:48:03 +00001547 if (skb_linearize(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 return 0;
1549
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001550 msg = (struct nd_msg *)skb_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001552 __skb_push(skb, skb->data - skb_transport_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001554 if (ipv6_hdr(skb)->hop_limit != 255) {
Joe Perches675418d2012-05-16 19:28:38 +00001555 ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n",
1556 ipv6_hdr(skb)->hop_limit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 return 0;
1558 }
1559
1560 if (msg->icmph.icmp6_code != 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001561 ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n",
1562 msg->icmph.icmp6_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 return 0;
1564 }
1565
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001566 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 switch (msg->icmph.icmp6_type) {
1569 case NDISC_NEIGHBOUR_SOLICITATION:
1570 ndisc_recv_ns(skb);
1571 break;
1572
1573 case NDISC_NEIGHBOUR_ADVERTISEMENT:
1574 ndisc_recv_na(skb);
1575 break;
1576
1577 case NDISC_ROUTER_SOLICITATION:
1578 ndisc_recv_rs(skb);
1579 break;
1580
1581 case NDISC_ROUTER_ADVERTISEMENT:
1582 ndisc_router_discovery(skb);
1583 break;
1584
1585 case NDISC_REDIRECT:
1586 ndisc_redirect_rcv(skb);
1587 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 return 0;
1591}
1592
1593static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
1594{
Jiri Pirko351638e2013-05-28 01:30:21 +00001595 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001596 struct net *net = dev_net(dev);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001597 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 switch (event) {
1600 case NETDEV_CHANGEADDR:
1601 neigh_changeaddr(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001602 fib6_run_gc(0, net, false);
Hannes Frederic Sowa5cb04432012-11-06 16:46:20 +00001603 idev = in6_dev_get(dev);
1604 if (!idev)
1605 break;
1606 if (idev->cnf.ndisc_notify)
1607 ndisc_send_unsol_na(dev);
1608 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 break;
1610 case NETDEV_DOWN:
1611 neigh_ifdown(&nd_tbl, dev);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001612 fib6_run_gc(0, net, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 break;
Ben Hutchingsf47b9462011-04-15 13:46:02 +00001614 case NETDEV_NOTIFY_PEERS:
1615 ndisc_send_unsol_na(dev);
1616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 default:
1618 break;
1619 }
1620
1621 return NOTIFY_DONE;
1622}
1623
1624static struct notifier_block ndisc_netdev_notifier = {
1625 .notifier_call = ndisc_netdev_event,
1626};
1627
1628#ifdef CONFIG_SYSCTL
1629static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
1630 const char *func, const char *dev_name)
1631{
1632 static char warncomm[TASK_COMM_LEN];
1633 static int warned;
1634 if (strcmp(warncomm, current->comm) && warned < 5) {
1635 strcpy(warncomm, current->comm);
Joe Perchesf3213832012-05-15 14:11:53 +00001636 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 -07001637 warncomm, func,
1638 dev_name, ctl->procname,
1639 dev_name, ctl->procname);
1640 warned++;
1641 }
1642}
1643
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07001644int 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 -07001645{
1646 struct net_device *dev = ctl->extra1;
1647 struct inet6_dev *idev;
1648 int ret;
1649
Eric W. Biedermand12af672007-10-18 03:05:25 -07001650 if ((strcmp(ctl->procname, "retrans_time") == 0) ||
1651 (strcmp(ctl->procname, "base_reachable_time") == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
1653
Eric W. Biedermand12af672007-10-18 03:05:25 -07001654 if (strcmp(ctl->procname, "retrans_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001655 ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001656
1657 else if (strcmp(ctl->procname, "base_reachable_time") == 0)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001658 ret = neigh_proc_dointvec_jiffies(ctl, write,
1659 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001660
1661 else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
YOSHIFUJI Hideakiad02ac12007-10-29 01:32:23 -07001662 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01001663 ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
1664 buffer, lenp, ppos);
Eric W. Biedermand12af672007-10-18 03:05:25 -07001665 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 ret = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
Jiri Pirko1f9248e52013-12-07 19:26:53 +01001669 if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
1670 idev->nd_parms->reachable_time =
1671 neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 idev->tstamp = jiffies;
1673 inet6_ifinfo_notify(RTM_NEWLINK, idev);
1674 in6_dev_put(idev);
1675 }
1676 return ret;
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680#endif
1681
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001682static int __net_init ndisc_net_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683{
1684 struct ipv6_pinfo *np;
1685 struct sock *sk;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001686 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001688 err = inet_ctl_sock_create(&sk, PF_INET6,
1689 SOCK_RAW, IPPROTO_ICMPV6, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 if (err < 0) {
Joe Perches675418d2012-05-16 19:28:38 +00001691 ND_PRINTK(0, err,
1692 "NDISC: Failed to initialize the control socket (err %d)\n",
1693 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 return err;
1695 }
1696
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001697 net->ipv6.ndisc_sk = sk;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 np->hop_limit = 255;
1701 /* Do not loopback ndisc messages */
1702 np->mc_loop = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001704 return 0;
1705}
1706
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001707static void __net_exit ndisc_net_exit(struct net *net)
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001708{
Denis V. Lunev1ed85162008-04-03 14:31:03 -07001709 inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001710}
1711
1712static struct pernet_operations ndisc_net_ops = {
1713 .init = ndisc_net_init,
1714 .exit = ndisc_net_exit,
1715};
1716
1717int __init ndisc_init(void)
1718{
1719 int err;
1720
1721 err = register_pernet_subsys(&ndisc_net_ops);
1722 if (err)
1723 return err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001724 /*
1725 * Initialize the neighbour table
1726 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 neigh_table_init(&nd_tbl);
1728
1729#ifdef CONFIG_SYSCTL
Jiri Pirko73af6142013-12-07 19:26:55 +01001730 err = neigh_sysctl_register(NULL, &nd_tbl.parms,
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08001731 &ndisc_ifinfo_sysctl_change);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001732 if (err)
1733 goto out_unregister_pernet;
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001734out:
Fabio Estevambcd081a2013-11-16 00:52:08 -02001735#endif
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001736 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001738#ifdef CONFIG_SYSCTL
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001739out_unregister_pernet:
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001740 unregister_pernet_subsys(&ndisc_net_ops);
1741 goto out;
Michal Kubeček2c861cc2013-09-09 21:45:04 +02001742#endif
1743}
1744
1745int __init ndisc_late_init(void)
1746{
1747 return register_netdevice_notifier(&ndisc_netdev_notifier);
1748}
1749
1750void ndisc_late_cleanup(void)
1751{
1752 unregister_netdevice_notifier(&ndisc_netdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753}
1754
1755void ndisc_cleanup(void)
1756{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757#ifdef CONFIG_SYSCTL
1758 neigh_sysctl_unregister(&nd_tbl.parms);
1759#endif
1760 neigh_table_clear(&nd_tbl);
Daniel Lezcano1762f7e2008-03-07 11:15:34 -08001761 unregister_pernet_subsys(&ndisc_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762}