Blame view

net/ipv6/ndisc.c 47.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *	Neighbour Discovery for IPv6
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3
   *	Linux INET6 implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Pedro Roque		<roque@di.fc.ul.pt>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
   *	Mike Shaver		<shaver@ingenia.com>
   *
   *	This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
   *      2 of the License, or (at your option) any later version.
   */
  
  /*
   *	Changes:
   *
e35f30c13   Alexey I. Froloff   Treat ND option 3...
18
   *	Alexey I. Froloff		:	RFC6106 (DNSSL) support
31910575a   Pierre Ynard   [IPv6]: Export us...
19
20
   *	Pierre Ynard			:	export userland ND options
   *						through netlink (RDNSS support)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
   *	Lars Fenneberg			:	fixed MTU setting on receipt
   *						of an RA.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
   *	Janos Farkas			:	kmalloc failure checks
   *	Alexey Kuznetsov		:	state machine reworked
   *						and moved to net/core.
   *	Pekka Savola			:	RFC2461 validation
   *	YOSHIFUJI Hideaki @USAGI	:	Verify ND options properly
   */
675418d51   Joe Perches   net: ipv6: ndisc:...
29
  #define pr_fmt(fmt) "ICMPv6: " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
41
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/sched.h>
  #include <linux/net.h>
  #include <linux/in6.h>
  #include <linux/route.h>
  #include <linux/init.h>
  #include <linux/rcupdate.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
42
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
1823730fb   Thomas Graf   [IPv4]: Move inte...
46
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  #include <linux/if_arp.h>
  #include <linux/ipv6.h>
  #include <linux/icmpv6.h>
  #include <linux/jhash.h>
  
  #include <net/sock.h>
  #include <net/snmp.h>
  
  #include <net/ipv6.h>
  #include <net/protocol.h>
  #include <net/ndisc.h>
  #include <net/ip6_route.h>
  #include <net/addrconf.h>
  #include <net/icmp.h>
31910575a   Pierre Ynard   [IPv6]: Export us...
61
62
  #include <net/netlink.h>
  #include <linux/rtnetlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  #include <net/flow.h>
  #include <net/ip6_checksum.h>
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
65
  #include <net/inet_common.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
  #include <linux/proc_fs.h>
  
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv6.h>
d6bf78171   Eric Dumazet   net neigh: RCU co...
70
71
  static u32 ndisc_hash(const void *pkey,
  		      const struct net_device *dev,
2c2aba6c5   David S. Miller   ipv6: Use univers...
72
  		      __u32 *hash_rnd);
60395a20f   Eric W. Biederman   neigh: Factor out...
73
  static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
  static int ndisc_constructor(struct neighbour *neigh);
  static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
  static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
  static int pndisc_constructor(struct pneigh_entry *n);
  static void pndisc_destructor(struct pneigh_entry *n);
  static void pndisc_redo(struct sk_buff *skb);
89d69d2b7   Stephen Hemminger   net: make neigh_o...
80
  static const struct neigh_ops ndisc_generic_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
  	.family =		AF_INET6,
  	.solicit =		ndisc_solicit,
  	.error_report =		ndisc_error_report,
  	.output =		neigh_resolve_output,
  	.connected_output =	neigh_connected_output,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  };
89d69d2b7   Stephen Hemminger   net: make neigh_o...
87
  static const struct neigh_ops ndisc_hh_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
  	.family =		AF_INET6,
  	.solicit =		ndisc_solicit,
  	.error_report =		ndisc_error_report,
  	.output =		neigh_resolve_output,
  	.connected_output =	neigh_resolve_output,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  };
89d69d2b7   Stephen Hemminger   net: make neigh_o...
94
  static const struct neigh_ops ndisc_direct_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	.family =		AF_INET6,
8f40b161d   David S. Miller   neigh: Pass neigh...
96
97
  	.output =		neigh_direct_output,
  	.connected_output =	neigh_direct_output,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
  };
  
  struct neigh_table nd_tbl = {
  	.family =	AF_INET6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	.key_len =	sizeof(struct in6_addr),
bdf53c584   Eric W. Biederman   neigh: Don't requ...
103
  	.protocol =	cpu_to_be16(ETH_P_IPV6),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	.hash =		ndisc_hash,
60395a20f   Eric W. Biederman   neigh: Factor out...
105
  	.key_eq =	ndisc_key_eq,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
110
111
  	.constructor =	ndisc_constructor,
  	.pconstructor =	pndisc_constructor,
  	.pdestructor =	pndisc_destructor,
  	.proxy_redo =	pndisc_redo,
  	.id =		"ndisc_cache",
  	.parms = {
b672083ed   Shan Wei   ipv6: use ND_REAC...
112
  		.tbl			= &nd_tbl,
b672083ed   Shan Wei   ipv6: use ND_REAC...
113
  		.reachable_time		= ND_REACHABLE_TIME,
1f9248e56   Jiri Pirko   neigh: convert pa...
114
115
116
117
118
119
120
121
122
123
124
125
  		.data = {
  			[NEIGH_VAR_MCAST_PROBES] = 3,
  			[NEIGH_VAR_UCAST_PROBES] = 3,
  			[NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
  			[NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
  			[NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
  			[NEIGH_VAR_GC_STALETIME] = 60 * HZ,
  			[NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
  			[NEIGH_VAR_PROXY_QLEN] = 64,
  			[NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
  			[NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
  		},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
  	},
  	.gc_interval =	  30 * HZ,
  	.gc_thresh1 =	 128,
  	.gc_thresh2 =	 512,
  	.gc_thresh3 =	1024,
  };
c48506877   David Ahern   net: Export fib6_...
132
  EXPORT_SYMBOL_GPL(nd_tbl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

cc84b3c6b   Alexander Aring   ipv6: export seve...
134
135
  void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
  			      int data_len, int pad)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
8ec5da415   Alexander Aring   ndisc: add __ndis...
137
  	int space = __ndisc_opt_addr_space(data_len, pad);
5f5a01156   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make ndisc...
138
  	u8 *opt = skb_put(skb, space);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
148
149
  
  	opt[0] = type;
  	opt[1] = space>>3;
  
  	memset(opt + 2, 0, pad);
  	opt   += pad;
  	space -= pad;
  
  	memcpy(opt+2, data, data_len);
  	data_len += 2;
  	opt += data_len;
e5d08d718   Ian Morris   ipv6: coding styl...
150
151
  	space -= data_len;
  	if (space > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		memset(opt, 0, space);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  }
cc84b3c6b   Alexander Aring   ipv6: export seve...
154
  EXPORT_SYMBOL_GPL(__ndisc_fill_addr_option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155

8ec5da415   Alexander Aring   ndisc: add __ndis...
156
  static inline void ndisc_fill_addr_option(struct sk_buff *skb, int type,
f997c55c1   Alexander Aring   ipv6: introduce n...
157
  					  void *data, u8 icmp6_type)
8ec5da415   Alexander Aring   ndisc: add __ndis...
158
159
160
  {
  	__ndisc_fill_addr_option(skb, type, data, skb->dev->addr_len,
  				 ndisc_addr_option_pad(skb->dev->type));
f997c55c1   Alexander Aring   ipv6: introduce n...
161
162
163
164
165
166
167
168
169
  	ndisc_ops_fill_addr_option(skb->dev, skb, icmp6_type);
  }
  
  static inline void ndisc_fill_redirect_addr_option(struct sk_buff *skb,
  						   void *ha,
  						   const u8 *ops_data)
  {
  	ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha, NDISC_REDIRECT);
  	ndisc_ops_fill_redirect_addr_option(skb->dev, skb, ops_data);
8ec5da415   Alexander Aring   ndisc: add __ndis...
170
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
176
177
178
179
  static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
  					    struct nd_opt_hdr *end)
  {
  	int type;
  	if (!cur || !end || cur >= end)
  		return NULL;
  	type = cur->nd_opt_type;
  	do {
  		cur = ((void *)cur) + (cur->nd_opt_len << 3);
67ba4152e   Ian Morris   ipv6: White-space...
180
  	} while (cur < end && cur->nd_opt_type != type);
a02cec215   Eric Dumazet   net: return opera...
181
  	return cur <= end && cur->nd_opt_type == type ? cur : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
f997c55c1   Alexander Aring   ipv6: introduce n...
183
184
  static inline int ndisc_is_useropt(const struct net_device *dev,
  				   struct nd_opt_hdr *opt)
31910575a   Pierre Ynard   [IPv6]: Export us...
185
  {
e35f30c13   Alexey I. Froloff   Treat ND option 3...
186
  	return opt->nd_opt_type == ND_OPT_RDNSS ||
f997c55c1   Alexander Aring   ipv6: introduce n...
187
188
  		opt->nd_opt_type == ND_OPT_DNSSL ||
  		ndisc_ops_is_useropt(dev, opt->nd_opt_type);
31910575a   Pierre Ynard   [IPv6]: Export us...
189
  }
f997c55c1   Alexander Aring   ipv6: introduce n...
190
191
  static struct nd_opt_hdr *ndisc_next_useropt(const struct net_device *dev,
  					     struct nd_opt_hdr *cur,
31910575a   Pierre Ynard   [IPv6]: Export us...
192
193
194
195
196
197
  					     struct nd_opt_hdr *end)
  {
  	if (!cur || !end || cur >= end)
  		return NULL;
  	do {
  		cur = ((void *)cur) + (cur->nd_opt_len << 3);
f997c55c1   Alexander Aring   ipv6: introduce n...
198
199
  	} while (cur < end && !ndisc_is_useropt(dev, cur));
  	return cur <= end && ndisc_is_useropt(dev, cur) ? cur : NULL;
31910575a   Pierre Ynard   [IPv6]: Export us...
200
  }
f997c55c1   Alexander Aring   ipv6: introduce n...
201
202
  struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
  					  u8 *opt, int opt_len,
30f2a5f37   David S. Miller   ipv6: Export ndis...
203
  					  struct ndisc_options *ndopts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
210
211
212
213
214
215
216
  {
  	struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
  
  	if (!nd_opt || opt_len < 0 || !ndopts)
  		return NULL;
  	memset(ndopts, 0, sizeof(*ndopts));
  	while (opt_len) {
  		int l;
  		if (opt_len < sizeof(struct nd_opt_hdr))
  			return NULL;
  		l = nd_opt->nd_opt_len << 3;
  		if (opt_len < l || l == 0)
  			return NULL;
f997c55c1   Alexander Aring   ipv6: introduce n...
217
218
  		if (ndisc_ops_parse_options(dev, nd_opt, ndopts))
  			goto next_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  		switch (nd_opt->nd_opt_type) {
  		case ND_OPT_SOURCE_LL_ADDR:
  		case ND_OPT_TARGET_LL_ADDR:
  		case ND_OPT_MTU:
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
223
  		case ND_OPT_NONCE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  		case ND_OPT_REDIRECT_HDR:
  			if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
675418d51   Joe Perches   net: ipv6: ndisc:...
226
227
228
229
  				ND_PRINTK(2, warn,
  					  "%s: duplicated ND6 option found: type=%d
  ",
  					  __func__, nd_opt->nd_opt_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
  			} else {
  				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
  			}
  			break;
  		case ND_OPT_PREFIX_INFO:
  			ndopts->nd_opts_pi_end = nd_opt;
cfcabdcc2   Stephen Hemminger   [NET]: sparse war...
236
  			if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
  				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
  			break;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
239
240
241
242
243
244
245
  #ifdef CONFIG_IPV6_ROUTE_INFO
  		case ND_OPT_ROUTE_INFO:
  			ndopts->nd_opts_ri_end = nd_opt;
  			if (!ndopts->nd_opts_ri)
  				ndopts->nd_opts_ri = nd_opt;
  			break;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  		default:
f997c55c1   Alexander Aring   ipv6: introduce n...
247
  			if (ndisc_is_useropt(dev, nd_opt)) {
31910575a   Pierre Ynard   [IPv6]: Export us...
248
249
250
251
252
253
254
255
256
  				ndopts->nd_useropts_end = nd_opt;
  				if (!ndopts->nd_useropts)
  					ndopts->nd_useropts = nd_opt;
  			} else {
  				/*
  				 * Unknown options must be silently ignored,
  				 * to accommodate future extension to the
  				 * protocol.
  				 */
675418d51   Joe Perches   net: ipv6: ndisc:...
257
258
259
260
261
262
  				ND_PRINTK(2, notice,
  					  "%s: ignored unsupported option; type=%d, len=%d
  ",
  					  __func__,
  					  nd_opt->nd_opt_type,
  					  nd_opt->nd_opt_len);
31910575a   Pierre Ynard   [IPv6]: Export us...
263
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  		}
f997c55c1   Alexander Aring   ipv6: introduce n...
265
  next_opt:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
  		opt_len -= l;
  		nd_opt = ((void *)nd_opt) + l;
  	}
  	return ndopts;
  }
b71d1d426   Eric Dumazet   inet: constify ip...
271
  int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
  {
  	switch (dev->type) {
  	case ARPHRD_ETHER:
  	case ARPHRD_IEEE802:	/* Not sure. Check it later. --ANK */
  	case ARPHRD_FDDI:
  		ipv6_eth_mc_map(addr, buf);
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
  	case ARPHRD_ARCNET:
  		ipv6_arcnet_mc_map(addr, buf);
  		return 0;
  	case ARPHRD_INFINIBAND:
a9e527e3f   Rolf Manderscheid   IPoIB: improve IP...
283
  		ipv6_ib_mc_map(addr, dev->broadcast, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  		return 0;
93ca3bb5d   Timo Teräs   net: gre: provide...
285
286
  	case ARPHRD_IPGRE:
  		return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
  	default:
  		if (dir) {
  			memcpy(buf, dev->broadcast, dev->addr_len);
  			return 0;
  		}
  	}
  	return -EINVAL;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
295
  EXPORT_SYMBOL(ndisc_mc_map);
d6bf78171   Eric Dumazet   net neigh: RCU co...
296
297
  static u32 ndisc_hash(const void *pkey,
  		      const struct net_device *dev,
2c2aba6c5   David S. Miller   ipv6: Use univers...
298
  		      __u32 *hash_rnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  {
2c2aba6c5   David S. Miller   ipv6: Use univers...
300
  	return ndisc_hashfn(pkey, dev, hash_rnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  }
60395a20f   Eric W. Biederman   neigh: Factor out...
302
303
304
305
  static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
  {
  	return neigh_key_eq128(n, pkey);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  static int ndisc_constructor(struct neighbour *neigh)
  {
67ba4152e   Ian Morris   ipv6: White-space...
308
  	struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  	struct net_device *dev = neigh->dev;
  	struct inet6_dev *in6_dev;
  	struct neigh_parms *parms;
a50feda54   Eric Dumazet   ipv6: bool/const ...
312
  	bool is_multicast = ipv6_addr_is_multicast(addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  	in6_dev = in6_dev_get(dev);
63159f29b   Ian Morris   ipv6: coding styl...
315
  	if (!in6_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
  		return -EINVAL;
  	}
  
  	parms = in6_dev->nd_parms;
  	__neigh_parms_put(neigh->parms);
  	neigh->parms = neigh_parms_clone(parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
  
  	neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
324
  	if (!dev->header_ops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
  		neigh->nud_state = NUD_NOARP;
  		neigh->ops = &ndisc_direct_ops;
8f40b161d   David S. Miller   neigh: Pass neigh...
327
  		neigh->output = neigh_direct_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
339
340
  	} else {
  		if (is_multicast) {
  			neigh->nud_state = NUD_NOARP;
  			ndisc_mc_map(addr, neigh->ha, dev, 1);
  		} else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
  			neigh->nud_state = NUD_NOARP;
  			memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
  			if (dev->flags&IFF_LOOPBACK)
  				neigh->type = RTN_LOCAL;
  		} else if (dev->flags&IFF_POINTOPOINT) {
  			neigh->nud_state = NUD_NOARP;
  			memcpy(neigh->ha, dev->broadcast, dev->addr_len);
  		}
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
341
  		if (dev->header_ops->cache)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  			neigh->ops = &ndisc_hh_ops;
  		else
  			neigh->ops = &ndisc_generic_ops;
  		if (neigh->nud_state&NUD_VALID)
  			neigh->output = neigh->ops->connected_output;
  		else
  			neigh->output = neigh->ops->output;
  	}
  	in6_dev_put(in6_dev);
  	return 0;
  }
  
  static int pndisc_constructor(struct pneigh_entry *n)
  {
67ba4152e   Ian Morris   ipv6: White-space...
356
  	struct in6_addr *addr = (struct in6_addr *)&n->key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  	struct in6_addr maddr;
  	struct net_device *dev = n->dev;
63159f29b   Ian Morris   ipv6: coding styl...
359
  	if (!dev || !__in6_dev_get(dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
364
365
366
367
  		return -EINVAL;
  	addrconf_addr_solict_mult(addr, &maddr);
  	ipv6_dev_mc_inc(dev, &maddr);
  	return 0;
  }
  
  static void pndisc_destructor(struct pneigh_entry *n)
  {
67ba4152e   Ian Morris   ipv6: White-space...
368
  	struct in6_addr *addr = (struct in6_addr *)&n->key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
  	struct in6_addr maddr;
  	struct net_device *dev = n->dev;
63159f29b   Ian Morris   ipv6: coding styl...
371
  	if (!dev || !__in6_dev_get(dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
  		return;
  	addrconf_addr_solict_mult(addr, &maddr);
  	ipv6_dev_mc_dec(dev, &maddr);
  }
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
376
377
378
379
380
381
382
  static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
  				       int len)
  {
  	int hlen = LL_RESERVED_SPACE(dev);
  	int tlen = dev->needed_tailroom;
  	struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
  	struct sk_buff *skb;
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
383

25a6e6b84   Thomas Graf   ipv6: Don't depen...
384
  	skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
385
  	if (!skb) {
25a6e6b84   Thomas Graf   ipv6: Don't depen...
386
387
388
  		ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb
  ",
  			  __func__);
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
389
390
  		return NULL;
  	}
f382d03ad   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Set skb->d...
391
392
  	skb->protocol = htons(ETH_P_IPV6);
  	skb->dev = dev;
527a150fb   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Defer buil...
393
  	skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
5135e633f   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Reset skb-...
394
  	skb_reset_transport_header(skb);
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
395

25a6e6b84   Thomas Graf   ipv6: Don't depen...
396
397
398
399
  	/* Manually assign socket ownership as we avoid calling
  	 * sock_alloc_send_pskb() to bypass wmem buffer limits
  	 */
  	skb_set_owner_w(skb, sk);
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
400
401
  	return skb;
  }
f382d03ad   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Set skb->d...
402
  static void ip6_nd_hdr(struct sk_buff *skb,
2576f17df   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Unshare ip6...
403
404
  		       const struct in6_addr *saddr,
  		       const struct in6_addr *daddr,
c8d6c380d   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Simplify a...
405
  		       int hop_limit, int len)
2576f17df   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Unshare ip6...
406
407
  {
  	struct ipv6hdr *hdr;
527a150fb   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Defer buil...
408
  	skb_push(skb, sizeof(*hdr));
2576f17df   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Unshare ip6...
409
  	skb_reset_network_header(skb);
2576f17df   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Unshare ip6...
410
411
412
413
414
  	hdr = ipv6_hdr(skb);
  
  	ip6_flow_hdr(hdr, 0, 0);
  
  	hdr->payload_len = htons(len);
c8d6c380d   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Simplify a...
415
416
  	hdr->nexthdr = IPPROTO_ICMPV6;
  	hdr->hop_limit = hop_limit;
2576f17df   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Unshare ip6...
417
418
419
420
  
  	hdr->saddr = *saddr;
  	hdr->daddr = *daddr;
  }
af9a99762   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Remove dev...
421
  static void ndisc_send_skb(struct sk_buff *skb,
fd0ea7dbf   YOSHIFUJI Hideaki   ndisc: Unexport n...
422
  			   const struct in6_addr *daddr,
aa4bdd4b3   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Remove icm...
423
  			   const struct in6_addr *saddr)
305d552ac   Brian Haley   bonding: send IPv...
424
  {
f4de84c64   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use ndisc_...
425
  	struct dst_entry *dst = skb_dst(skb);
af9a99762   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Remove dev...
426
  	struct net *net = dev_net(skb->dev);
7b3d9b06d   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Fill in IC...
427
  	struct sock *sk = net->ipv6.ndisc_sk;
305d552ac   Brian Haley   bonding: send IPv...
428
429
  	struct inet6_dev *idev;
  	int err;
aa4bdd4b3   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Remove icm...
430
  	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
305d552ac   Brian Haley   bonding: send IPv...
431
432
433
  	u8 type;
  
  	type = icmp6h->icmp6_type;
f4de84c64   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use ndisc_...
434
  	if (!dst) {
f4de84c64   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use ndisc_...
435
  		struct flowi6 fl6;
e0d56fdd7   David Ahern   net: l3mdev: remo...
436
  		int oif = skb->dev->ifindex;
305d552ac   Brian Haley   bonding: send IPv...
437

ca254490c   David Ahern   net: Add VRF supp...
438
  		icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
f4de84c64   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use ndisc_...
439
440
441
442
443
444
445
446
  		dst = icmp6_dst_alloc(skb->dev, &fl6);
  		if (IS_ERR(dst)) {
  			kfree_skb(skb);
  			return;
  		}
  
  		skb_dst_set(skb, dst);
  	}
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
447

7b3d9b06d   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Fill in IC...
448
449
450
451
452
453
  	icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
  					      IPPROTO_ICMPV6,
  					      csum_partial(icmp6h,
  							   skb->len, 0));
  
  	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
cfdf76474   Eric Dumazet   ipv6: some RCU co...
454
455
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
edf391ff1   Neil Horman   snmp: add missing...
456
  	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
457

29a26a568   Eric W. Biederman   netfilter: Pass s...
458
459
  	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
  		      net, sk, skb, NULL, dst->dev,
13206b6bf   Eric W. Biederman   net: Pass net int...
460
  		      dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	if (!err) {
5c5d244bd   Denis V. Lunev   ipv6: added net a...
462
  		ICMP6MSGOUT_INC_STATS(net, idev, type);
a862f6a6d   Denis V. Lunev   ipv6: added net a...
463
  		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	}
cfdf76474   Eric Dumazet   ipv6: some RCU co...
465
  	rcu_read_unlock();
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
466
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467

38cf595b1   Jiri Benc   ipv6: remove unus...
468
  void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
f564f45c4   Cong Wang   vxlan: add ipv6 p...
469
470
  		   const struct in6_addr *solicited_addr,
  		   bool router, bool solicited, bool override, bool inc_opt)
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
471
  {
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
472
  	struct sk_buff *skb;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
473
474
  	struct in6_addr tmpaddr;
  	struct inet6_ifaddr *ifp;
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
475
  	const struct in6_addr *src_addr;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
476
477
  	struct nd_msg *msg;
  	int optlen = 0;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
478
479
  
  	/* for anycast or proxy, solicited_addr != src_addr */
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
480
  	ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
481
482
483
  	if (ifp) {
  		src_addr = solicited_addr;
  		if (ifp->flags & IFA_F_OPTIMISTIC)
f2f79cca1   Daniel Baluta   ndisc: bool initi...
484
  			override = false;
9f888160b   stephen hemminger   ipv6: fix NULL re...
485
  		inc_opt |= ifp->idev->cnf.force_tllao;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
486
487
  		in6_ifa_put(ifp);
  	} else {
191cd5825   Brian Haley   netns: Add networ...
488
  		if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
489
  				       inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
490
  				       &tmpaddr))
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
491
492
493
  			return;
  		src_addr = &tmpaddr;
  	}
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
494
495
496
  	if (!dev->addr_len)
  		inc_opt = 0;
  	if (inc_opt)
f997c55c1   Alexander Aring   ipv6: introduce n...
497
498
  		optlen += ndisc_opt_addr_space(dev,
  					       NDISC_NEIGHBOUR_ADVERTISEMENT);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
499

1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
500
  	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
501
502
  	if (!skb)
  		return;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
503
504
505
506
507
508
509
510
511
512
513
514
515
  	msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
  	*msg = (struct nd_msg) {
  		.icmph = {
  			.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
  			.icmp6_router = router,
  			.icmp6_solicited = solicited,
  			.icmp6_override = override,
  		},
  		.target = *solicited_addr,
  	};
  
  	if (inc_opt)
  		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
f997c55c1   Alexander Aring   ipv6: introduce n...
516
517
  				       dev->dev_addr,
  				       NDISC_NEIGHBOUR_ADVERTISEMENT);
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
518

b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
519
  	ndisc_send_skb(skb, daddr, src_addr);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
520
  }
f47b94646   Ben Hutchings   ipv6: Send unsoli...
521
522
523
524
  static void ndisc_send_unsol_na(struct net_device *dev)
  {
  	struct inet6_dev *idev;
  	struct inet6_ifaddr *ifa;
f47b94646   Ben Hutchings   ipv6: Send unsoli...
525
526
527
528
529
530
531
  
  	idev = in6_dev_get(dev);
  	if (!idev)
  		return;
  
  	read_lock_bh(&idev->lock);
  	list_for_each_entry(ifa, &idev->addr_list, if_list) {
38cf595b1   Jiri Benc   ipv6: remove unus...
532
  		ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr,
f47b94646   Ben Hutchings   ipv6: Send unsoli...
533
534
535
536
537
538
539
540
  			      /*router=*/ !!idev->cnf.forwarding,
  			      /*solicited=*/ false, /*override=*/ true,
  			      /*inc_opt=*/ true);
  	}
  	read_unlock_bh(&idev->lock);
  
  	in6_dev_put(idev);
  }
38cf595b1   Jiri Benc   ipv6: remove unus...
541
  void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
542
543
  		   const struct in6_addr *daddr, const struct in6_addr *saddr,
  		   u64 nonce)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  {
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
545
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  	struct in6_addr addr_buf;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
547
548
549
  	int inc_opt = dev->addr_len;
  	int optlen = 0;
  	struct nd_msg *msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550

63159f29b   Ian Morris   ipv6: coding styl...
551
  	if (!saddr) {
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
552
553
  		if (ipv6_get_lladdr(dev, &addr_buf,
  				   (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
  			return;
  		saddr = &addr_buf;
  	}
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
557
  	if (ipv6_addr_any(saddr))
f2f79cca1   Daniel Baluta   ndisc: bool initi...
558
  		inc_opt = false;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
559
  	if (inc_opt)
f997c55c1   Alexander Aring   ipv6: introduce n...
560
561
  		optlen += ndisc_opt_addr_space(dev,
  					       NDISC_NEIGHBOUR_SOLICITATION);
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
562
563
  	if (nonce != 0)
  		optlen += 8;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
564
565
  
  	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
566
567
  	if (!skb)
  		return;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
568
569
570
571
572
573
574
575
576
577
  	msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
  	*msg = (struct nd_msg) {
  		.icmph = {
  			.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
  		},
  		.target = *solicit,
  	};
  
  	if (inc_opt)
  		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
f997c55c1   Alexander Aring   ipv6: introduce n...
578
579
  				       dev->dev_addr,
  				       NDISC_NEIGHBOUR_SOLICITATION);
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
580
581
582
583
584
585
586
  	if (nonce != 0) {
  		u8 *opt = skb_put(skb, 8);
  
  		opt[0] = ND_OPT_NONCE;
  		opt[1] = 8 >> 3;
  		memcpy(opt + 2, &nonce, 6);
  	}
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
587

b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
588
  	ndisc_send_skb(skb, daddr, saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  }
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
590
591
  void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
  		   const struct in6_addr *daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  {
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
593
  	struct sk_buff *skb;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
594
  	struct rs_msg *msg;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
595
  	int send_sllao = dev->addr_len;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
596
  	int optlen = 0;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
597
598
599
600
601
602
603
604
  
  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
  	/*
  	 * According to section 2.2 of RFC 4429, we must not
  	 * send router solicitations with a sllao from
  	 * optimistic addresses, but we may send the solicitation
  	 * if we don't include the sllao.  So here we check
  	 * if our address is optimistic, and if so, we
bea851954   Joe Perches   [IPV6]: Spelling ...
605
  	 * suppress the inclusion of the sllao.
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
606
607
  	 */
  	if (send_sllao) {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
608
  		struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
1cab3da6b   Daniel Lezcano   [NETNS][IPV6]: in...
609
  							   dev, 1);
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
610
611
  		if (ifp) {
  			if (ifp->flags & IFA_F_OPTIMISTIC)  {
ca0435693   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
612
  				send_sllao = 0;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
613
  			}
ca0435693   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
614
  			in6_ifa_put(ifp);
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
615
616
617
618
619
  		} else {
  			send_sllao = 0;
  		}
  	}
  #endif
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
620
  	if (send_sllao)
f997c55c1   Alexander Aring   ipv6: introduce n...
621
  		optlen += ndisc_opt_addr_space(dev, NDISC_ROUTER_SOLICITATION);
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
622
623
  
  	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
624
625
  	if (!skb)
  		return;
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
626
627
628
629
630
631
632
633
634
  	msg = (struct rs_msg *)skb_put(skb, sizeof(*msg));
  	*msg = (struct rs_msg) {
  		.icmph = {
  			.icmp6_type = NDISC_ROUTER_SOLICITATION,
  		},
  	};
  
  	if (send_sllao)
  		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
f997c55c1   Alexander Aring   ipv6: introduce n...
635
636
  				       dev->dev_addr,
  				       NDISC_ROUTER_SOLICITATION);
1cb3fe513   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
637

b44b5f4ae   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Break down...
638
  	ndisc_send_skb(skb, daddr, saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
640

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  
  static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
  {
  	/*
  	 *	"The sender MUST return an ICMP
  	 *	 destination unreachable"
  	 */
  	dst_link_failure(skb);
  	kfree_skb(skb);
  }
  
  /* Called with locked neigh: either read or both */
  
  static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
  {
  	struct in6_addr *saddr = NULL;
  	struct in6_addr mcaddr;
  	struct net_device *dev = neigh->dev;
  	struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
  	int probes = atomic_read(&neigh->probes);
c58da4c65   Erik Kline   net: ipv6: allow ...
661
662
663
  	if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
  					   dev, 1,
  					   IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
664
  		saddr = &ipv6_hdr(skb)->saddr;
e5d08d718   Ian Morris   ipv6: coding styl...
665
666
  	probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
  	if (probes < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  		if (!(neigh->nud_state & NUD_VALID)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
668
669
670
671
  			ND_PRINTK(1, dbg,
  				  "%s: trying to ucast probe in NUD_INVALID: %pI6
  ",
  				  __func__, target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  		}
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
673
  		ndisc_send_ns(dev, target, target, saddr, 0);
1f9248e56   Jiri Pirko   neigh: convert pa...
674
  	} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  		neigh_app_ns(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
  	} else {
  		addrconf_addr_solict_mult(target, &mcaddr);
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
678
  		ndisc_send_ns(dev, target, &mcaddr, saddr, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
  	}
  }
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
681
682
  static int pndisc_is_router(const void *pkey,
  			    struct net_device *dev)
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
683
684
  {
  	struct pneigh_entry *n;
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
685
  	int ret = -1;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
686
687
  
  	read_lock_bh(&nd_tbl.lock);
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
688
689
690
  	n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
  	if (n)
  		ret = !!(n->flags & NTF_ROUTER);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
691
  	read_unlock_bh(&nd_tbl.lock);
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
692
  	return ret;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
693
  }
f997c55c1   Alexander Aring   ipv6: introduce n...
694
695
696
697
698
699
700
701
  void ndisc_update(const struct net_device *dev, struct neighbour *neigh,
  		  const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type,
  		  struct ndisc_options *ndopts)
  {
  	neigh_update(neigh, lladdr, new, flags);
  	/* report ndisc ops about neighbour update */
  	ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  static void ndisc_recv_ns(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
704
  	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
705
706
  	const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
  	const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  	u8 *lladdr = NULL;
29a3cad5c   Simon Horman   ipv6: Correct com...
708
  	u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
709
  				    offsetof(struct nd_msg, opt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
712
713
714
715
  	struct ndisc_options ndopts;
  	struct net_device *dev = skb->dev;
  	struct inet6_ifaddr *ifp;
  	struct inet6_dev *idev = NULL;
  	struct neighbour *neigh;
  	int dad = ipv6_addr_any(saddr);
a50feda54   Eric Dumazet   ipv6: bool/const ...
716
  	bool inc;
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
717
  	int is_router = -1;
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
718
  	u64 nonce = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719

115b0aa6b   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Check NS m...
720
721
722
723
724
  	if (skb->len < sizeof(struct nd_msg)) {
  		ND_PRINTK(2, warn, "NS: packet too short
  ");
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  	if (ipv6_addr_is_multicast(&msg->target)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
726
727
  		ND_PRINTK(2, warn, "NS: multicast target address
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
731
732
733
734
  		return;
  	}
  
  	/*
  	 * RFC2461 7.1.1:
  	 * DAD has to be destined for solicited node multicast address.
  	 */
ca97a644d   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Introduce i...
735
  	if (dad && !ipv6_addr_is_solict_mult(daddr)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
736
737
  		ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
  		return;
  	}
f997c55c1   Alexander Aring   ipv6: introduce n...
740
  	if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
741
742
  		ND_PRINTK(2, warn, "NS: invalid ND options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
  		return;
  	}
  
  	if (ndopts.nd_opts_src_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
  		if (!lladdr) {
675418d51   Joe Perches   net: ipv6: ndisc:...
749
750
751
  			ND_PRINTK(2, warn,
  				  "NS: invalid link-layer address length
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
  			return;
  		}
  
  		/* RFC2461 7.1.1:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
756
757
  		 *	If the IP source address is the unspecified address,
  		 *	there MUST NOT be source link-layer address option
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
  		 *	in the message.
  		 */
  		if (dad) {
675418d51   Joe Perches   net: ipv6: ndisc:...
761
762
763
  			ND_PRINTK(2, warn,
  				  "NS: bad DAD packet (link-layer address option)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
  			return;
  		}
  	}
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
767
768
  	if (ndopts.nd_opts_nonce)
  		memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  
  	inc = ipv6_addr_is_multicast(daddr);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
771
  	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
772
  	if (ifp) {
ca254490c   David Ahern   net: Add VRF supp...
773
  have_ifp:
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
774
775
  		if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
  			if (dad) {
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
776
777
778
779
780
781
782
783
784
785
  				if (nonce != 0 && ifp->dad_nonce == nonce) {
  					u8 *np = (u8 *)&nonce;
  					/* Matching nonce if looped back */
  					ND_PRINTK(2, notice,
  						  "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored
  ",
  						  ifp->idev->dev->name,
  						  &ifp->addr, np);
  					goto out;
  				}
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
786
787
788
789
790
791
  				/*
  				 * We are colliding with another node
  				 * who is doing DAD
  				 * so fail our DAD process
  				 */
  				addrconf_dad_failure(ifp);
9e3be4b34   Denis V. Lunev   [IPV6]: Freeing a...
792
  				return;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
793
794
795
796
797
798
799
800
  			} else {
  				/*
  				 * This is not a dad solicitation.
  				 * If we are an optimistic node,
  				 * we should respond.
  				 * Otherwise, we should ignore it.
  				 */
  				if (!(ifp->flags & IFA_F_OPTIMISTIC))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
  		}
  
  		idev = ifp->idev;
  	} else {
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
807
  		struct net *net = dev_net(dev);
ca254490c   David Ahern   net: Add VRF supp...
808
809
810
811
812
813
814
815
816
817
818
  		/* perhaps an address on the master device */
  		if (netif_is_l3_slave(dev)) {
  			struct net_device *mdev;
  
  			mdev = netdev_master_upper_dev_get_rcu(dev);
  			if (mdev) {
  				ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);
  				if (ifp)
  					goto have_ifp;
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
822
823
  		idev = in6_dev_get(dev);
  		if (!idev) {
  			/* XXX: count this drop? */
  			return;
  		}
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
824
  		if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
825
  		    (idev->cnf.forwarding &&
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
826
  		     (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
827
  		     (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
828
  			if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  			    skb->pkt_type != PACKET_HOST &&
f2f79cca1   Daniel Baluta   ndisc: bool initi...
830
  			    inc &&
1f9248e56   Jiri Pirko   neigh: convert pa...
831
  			    NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
  				/*
  				 * for anycast or proxy,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
834
835
  				 * sender should delay its response
  				 * by a random time between 0 and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
844
845
846
  				 * MAX_ANYCAST_DELAY_TIME seconds.
  				 * (RFC2461) -- yoshfuji
  				 */
  				struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
  				if (n)
  					pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
  				goto out;
  			}
  		} else
  			goto out;
  	}
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
847
  	if (is_router < 0)
fb568637e   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make sever...
848
  		is_router = idev->cnf.forwarding;
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
849

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  	if (dad) {
38cf595b1   Jiri Benc   ipv6: remove unus...
851
  		ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target,
fb568637e   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make sever...
852
  			      !!is_router, false, (ifp != NULL), true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
  		goto out;
  	}
  
  	if (inc)
  		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
  	else
  		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
860
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
865
866
  	 *	update / create cache entry
  	 *	for the source address
  	 */
  	neigh = __neigh_lookup(&nd_tbl, saddr, dev,
  			       !inc || lladdr || !dev->addr_len);
  	if (neigh)
f997c55c1   Alexander Aring   ipv6: introduce n...
867
  		ndisc_update(dev, neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
f997c55c1   Alexander Aring   ipv6: introduce n...
869
870
  			     NEIGH_UPDATE_F_OVERRIDE,
  			     NDISC_NEIGHBOUR_SOLICITATION, &ndopts);
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
871
  	if (neigh || !dev->header_ops) {
38cf595b1   Jiri Benc   ipv6: remove unus...
872
  		ndisc_send_na(dev, saddr, &msg->target, !!is_router,
fb568637e   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make sever...
873
  			      true, (ifp != NULL && inc), inc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
  		if (neigh)
  			neigh_release(neigh);
  	}
  
  out:
  	if (ifp)
  		in6_ifa_put(ifp);
  	else
  		in6_dev_put(idev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
885
886
  }
  
  static void ndisc_recv_na(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
887
  	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
be7a010d6   Duan Jiong   ipv6: update Dest...
888
  	struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
b71d1d426   Eric Dumazet   inet: constify ip...
889
  	const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  	u8 *lladdr = NULL;
29a3cad5c   Simon Horman   ipv6: Correct com...
891
  	u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
892
  				    offsetof(struct nd_msg, opt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
  	struct ndisc_options ndopts;
  	struct net_device *dev = skb->dev;
7a02bf892   Johannes Berg   ipv6: add option ...
895
  	struct inet6_dev *idev = __in6_dev_get(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
  	struct inet6_ifaddr *ifp;
  	struct neighbour *neigh;
  
  	if (skb->len < sizeof(struct nd_msg)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
900
901
  		ND_PRINTK(2, warn, "NA: packet too short
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
905
  		return;
  	}
  
  	if (ipv6_addr_is_multicast(&msg->target)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
906
907
  		ND_PRINTK(2, warn, "NA: target address is multicast
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
  		return;
  	}
  
  	if (ipv6_addr_is_multicast(daddr) &&
  	    msg->icmph.icmp6_solicited) {
675418d51   Joe Perches   net: ipv6: ndisc:...
913
914
  		ND_PRINTK(2, warn, "NA: solicited NA is multicasted
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
  		return;
  	}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
917

7a02bf892   Johannes Berg   ipv6: add option ...
918
919
920
921
922
923
924
  	/* For some 802.11 wireless deployments (and possibly other networks),
  	 * there will be a NA proxy and unsolicitd packets are attacks
  	 * and thus should not be accepted.
  	 */
  	if (!msg->icmph.icmp6_solicited && idev &&
  	    idev->cnf.drop_unsolicited_na)
  		return;
f997c55c1   Alexander Aring   ipv6: introduce n...
925
  	if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
926
927
  		ND_PRINTK(2, warn, "NS: invalid ND option
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
  		return;
  	}
  	if (ndopts.nd_opts_tgt_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
  		if (!lladdr) {
675418d51   Joe Perches   net: ipv6: ndisc:...
933
934
935
  			ND_PRINTK(2, warn,
  				  "NA: invalid link-layer address length
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
  			return;
  		}
  	}
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
939
  	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
940
  	if (ifp) {
bd015928b   Daniel Walter   ipv6: ignore loop...
941
942
943
944
  		if (skb->pkt_type != PACKET_LOOPBACK
  		    && (ifp->flags & IFA_F_TENTATIVE)) {
  				addrconf_dad_failure(ifp);
  				return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
948
949
  		}
  		/* What should we make now? The advertisement
  		   is invalid, but ndisc specs say nothing
  		   about it. It could be misconfiguration, or
  		   an smart proxy agent tries to help us :-)
24fc7b86d   Jan Sembera   ipv6: silence log...
950
951
952
953
  
  		   We should not print the error if NA has been
  		   received from loopback - it is just our own
  		   unsolicited advertisement.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
  		 */
24fc7b86d   Jan Sembera   ipv6: silence log...
955
  		if (skb->pkt_type != PACKET_LOOPBACK)
675418d51   Joe Perches   net: ipv6: ndisc:...
956
957
958
959
  			ND_PRINTK(1, warn,
  				  "NA: someone advertises our address %pI6 on %s!
  ",
  				  &ifp->addr, ifp->idev->dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
966
  		in6_ifa_put(ifp);
  		return;
  	}
  	neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
  
  	if (neigh) {
  		u8 old_flags = neigh->flags;
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
967
  		struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
970
  
  		if (neigh->nud_state & NUD_FAILED)
  			goto out;
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
971
972
973
974
975
976
  		/*
  		 * Don't update the neighbor cache entry on a proxy NA from
  		 * ourselves because either the proxied node is off link or it
  		 * has already sent a NA to us.
  		 */
  		if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
977
978
  		    net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
  		    pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
b20b6d972   Nicolas Dichtel   ndisc: fix a typo...
979
  			/* XXX: idev->cnf.proxy_ndp */
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
980
  			goto out;
fbea49e1e   YOSHIFUJI Hideaki   [IPV6] NDISC: Add...
981
  		}
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
982

f997c55c1   Alexander Aring   ipv6: introduce n...
983
  		ndisc_update(dev, neigh, lladdr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
987
  			     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
  			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
f997c55c1   Alexander Aring   ipv6: introduce n...
988
989
  			     (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0),
  			     NDISC_NEIGHBOUR_ADVERTISEMENT, &ndopts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
992
993
994
  
  		if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
  			/*
  			 * Change: router to host
  			 */
be7a010d6   Duan Jiong   ipv6: update Dest...
995
  			rt6_clean_tohost(dev_net(dev),  saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
999
1000
1001
1002
1003
1004
  		}
  
  out:
  		neigh_release(neigh);
  	}
  }
  
  static void ndisc_recv_rs(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1005
  	struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
  	unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
  	struct neighbour *neigh;
  	struct inet6_dev *idev;
b71d1d426   Eric Dumazet   inet: constify ip...
1009
  	const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
1011
1012
1013
1014
  	struct ndisc_options ndopts;
  	u8 *lladdr = NULL;
  
  	if (skb->len < sizeof(*rs_msg))
  		return;
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1015
  	idev = __in6_dev_get(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  	if (!idev) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1017
1018
  		ND_PRINTK(1, err, "RS: can't find in6 device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  		return;
  	}
  
  	/* Don't accept RS if we're not in router mode */
  	if (!idev->cnf.forwarding)
  		goto out;
  
  	/*
  	 * Don't update NCE if src = ::;
  	 * this implies that the source node has no ip address assigned yet.
  	 */
  	if (ipv6_addr_any(saddr))
  		goto out;
  
  	/* Parse ND options */
f997c55c1   Alexander Aring   ipv6: introduce n...
1034
  	if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1035
1036
  		ND_PRINTK(2, notice, "NS: invalid ND option, ignored
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  		goto out;
  	}
  
  	if (ndopts.nd_opts_src_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
  					     skb->dev);
  		if (!lladdr)
  			goto out;
  	}
  
  	neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
  	if (neigh) {
f997c55c1   Alexander Aring   ipv6: introduce n...
1049
  		ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE|
f997c55c1   Alexander Aring   ipv6: introduce n...
1052
1053
  			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER,
  			     NDISC_ROUTER_SOLICITATION, &ndopts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
  		neigh_release(neigh);
  	}
  out:
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1057
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
  }
31910575a   Pierre Ynard   [IPv6]: Export us...
1059
1060
1061
1062
1063
1064
  static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
  {
  	struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
  	struct sk_buff *skb;
  	struct nlmsghdr *nlh;
  	struct nduseroptmsg *ndmsg;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1065
  	struct net *net = dev_net(ra->dev);
31910575a   Pierre Ynard   [IPv6]: Export us...
1066
1067
1068
1069
1070
1071
  	int err;
  	int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
  				    + (opt->nd_opt_len << 3));
  	size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));
  
  	skb = nlmsg_new(msg_size, GFP_ATOMIC);
63159f29b   Ian Morris   ipv6: coding styl...
1072
  	if (!skb) {
31910575a   Pierre Ynard   [IPv6]: Export us...
1073
1074
1075
1076
1077
  		err = -ENOBUFS;
  		goto errout;
  	}
  
  	nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
63159f29b   Ian Morris   ipv6: coding styl...
1078
  	if (!nlh) {
31910575a   Pierre Ynard   [IPv6]: Export us...
1079
1080
1081
1082
1083
  		goto nla_put_failure;
  	}
  
  	ndmsg = nlmsg_data(nlh);
  	ndmsg->nduseropt_family = AF_INET6;
dbb2ed248   Pierre Ynard   [IPV6]: Add ifind...
1084
  	ndmsg->nduseropt_ifindex = ra->dev->ifindex;
31910575a   Pierre Ynard   [IPv6]: Export us...
1085
1086
1087
1088
1089
  	ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
  	ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
  	ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
  
  	memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
930345ea6   Jiri Benc   netlink: implemen...
1090
  	if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr))
c78679e8f   David S. Miller   ipv6: Stop using ...
1091
  		goto nla_put_failure;
31910575a   Pierre Ynard   [IPv6]: Export us...
1092
  	nlmsg_end(skb, nlh);
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
1093
  	rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
31910575a   Pierre Ynard   [IPv6]: Export us...
1094
1095
1096
1097
1098
1099
  	return;
  
  nla_put_failure:
  	nlmsg_free(skb);
  	err = -EMSGSIZE;
  errout:
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
1100
  	rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
31910575a   Pierre Ynard   [IPv6]: Export us...
1101
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
  static void ndisc_router_discovery(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1104
  	struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
  	struct neighbour *neigh = NULL;
  	struct inet6_dev *in6_dev;
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1107
  	struct rt6_info *rt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
1110
  	int lifetime;
  	struct ndisc_options ndopts;
  	int optlen;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1111
  	unsigned int pref = 0;
a394eef56   Marius Tomaschewski   ipv6: send NEWLIN...
1112
  	__u32 old_if_flags;
2053aeb69   Marius Tomaschewski   ipv6: send only o...
1113
  	bool send_ifinfo_notify = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114

67ba4152e   Ian Morris   ipv6: White-space...
1115
  	__u8 *opt = (__u8 *)(ra_msg + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116

29a3cad5c   Simon Horman   ipv6: Correct com...
1117
1118
  	optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
  		sizeof(struct ra_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119

f2a762d8a   Ben Greear   ipv6: Add more de...
1120
1121
1122
1123
  	ND_PRINTK(2, info,
  		  "RA: %s, dev: %s
  ",
  		  __func__, skb->dev->name);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1124
  	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1125
1126
  		ND_PRINTK(2, warn, "RA: source address is not link-local
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
  		return;
  	}
  	if (optlen < 0) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1130
1131
  		ND_PRINTK(2, warn, "RA: packet too short
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1134
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1135
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1136
1137
  		ND_PRINTK(2, warn, "RA: from host or unauthorized router
  ");
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1138
1139
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1140
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1141

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
  	/*
  	 *	set the RA_RECV flag in the interface
  	 */
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1145
  	in6_dev = __in6_dev_get(skb->dev);
63159f29b   Ian Morris   ipv6: coding styl...
1146
  	if (!in6_dev) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1147
1148
1149
  		ND_PRINTK(0, err, "RA: can't find inet6 device for %s
  ",
  			  skb->dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152

f997c55c1   Alexander Aring   ipv6: introduce n...
1153
  	if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1154
1155
  		ND_PRINTK(2, warn, "RA: invalid ND options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
  		return;
  	}
f2a762d8a   Ben Greear   ipv6: Add more de...
1158
1159
1160
1161
1162
  	if (!ipv6_accept_ra(in6_dev)) {
  		ND_PRINTK(2, info,
  			  "RA: %s, did not accept ra for dev: %s
  ",
  			  __func__, skb->dev->name);
31ce8c71a   David Ward   ipv6: Update Neig...
1163
  		goto skip_linkparms;
f2a762d8a   Ben Greear   ipv6: Add more de...
1164
  	}
31ce8c71a   David Ward   ipv6: Update Neig...
1165

de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1166
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1167
  	/* skip link-specific parameters from interior routers */
f2a762d8a   Ben Greear   ipv6: Add more de...
1168
1169
1170
1171
1172
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
  		ND_PRINTK(2, info,
  			  "RA: %s, nodetype is NODEFAULT, dev: %s
  ",
  			  __func__, skb->dev->name);
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1173
  		goto skip_linkparms;
f2a762d8a   Ben Greear   ipv6: Add more de...
1174
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1175
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1176

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
  	if (in6_dev->if_flags & IF_RS_SENT) {
  		/*
  		 *	flag that an RA was received after an RS was sent
  		 *	out on this interface.
  		 */
  		in6_dev->if_flags |= IF_RA_RCVD;
  	}
  
  	/*
  	 * Remember the managed/otherconf flags from most recently
  	 * received RA message (RFC 2462) -- yoshfuji
  	 */
a394eef56   Marius Tomaschewski   ipv6: send NEWLIN...
1189
  	old_if_flags = in6_dev->if_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
1192
1193
1194
1195
  	in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED |
  				IF_RA_OTHERCONF)) |
  				(ra_msg->icmph.icmp6_addrconf_managed ?
  					IF_RA_MANAGED : 0) |
  				(ra_msg->icmph.icmp6_addrconf_other ?
  					IF_RA_OTHERCONF : 0);
a394eef56   Marius Tomaschewski   ipv6: send NEWLIN...
1196
  	if (old_if_flags != in6_dev->if_flags)
2053aeb69   Marius Tomaschewski   ipv6: send only o...
1197
  		send_ifinfo_notify = true;
a394eef56   Marius Tomaschewski   ipv6: send NEWLIN...
1198

f2a762d8a   Ben Greear   ipv6: Add more de...
1199
1200
1201
1202
1203
  	if (!in6_dev->cnf.accept_ra_defrtr) {
  		ND_PRINTK(2, info,
  			  "RA: %s, defrtr is false for dev: %s
  ",
  			  __func__, skb->dev->name);
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1204
  		goto skip_defrtr;
f2a762d8a   Ben Greear   ipv6: Add more de...
1205
  	}
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1206

d93331965   Ben Greear   ipv6: Allow accep...
1207
1208
1209
  	/* Do not accept RA with source-addr found on local machine unless
  	 * accept_ra_from_local is set to true.
  	 */
b64288171   Li RongQing   ipv6: fix the che...
1210
1211
  	if (!in6_dev->cnf.accept_ra_from_local &&
  	    ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
c1a9a291c   Hannes Frederic Sowa   ipv6: honor ifind...
1212
  			  in6_dev->dev, 0)) {
f2a762d8a   Ben Greear   ipv6: Add more de...
1213
  		ND_PRINTK(2, info,
d93331965   Ben Greear   ipv6: Allow accep...
1214
1215
1216
  			  "RA from local address detected on dev: %s: default router ignored
  ",
  			  skb->dev->name);
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1217
  		goto skip_defrtr;
f2a762d8a   Ben Greear   ipv6: Add more de...
1218
  	}
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1219

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
  	lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1221
1222
1223
  #ifdef CONFIG_IPV6_ROUTER_PREF
  	pref = ra_msg->icmph.icmp6_router_pref;
  	/* 10b is handled as if it were 00b (medium) */
930d6ff2e   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1224
  	if (pref == ICMPV6_ROUTER_PREF_INVALID ||
6d5b78cdd   YOSHIFUJI Hideaki   [IPV6] NDISC: Fix...
1225
  	    !in6_dev->cnf.accept_ra_rtr_pref)
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1226
1227
  		pref = ICMPV6_ROUTER_PREF_MEDIUM;
  #endif
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1228
  	rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229

eb857186e   David S. Miller   ipv6: ndisc: Conv...
1230
1231
1232
  	if (rt) {
  		neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
  		if (!neigh) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1233
1234
1235
1236
  			ND_PRINTK(0, err,
  				  "RA: %s got default router without neighbour
  ",
  				  __func__);
94e187c01   Amerigo Wang   ipv6: introduce i...
1237
  			ip6_rt_put(rt);
eb857186e   David S. Miller   ipv6: ndisc: Conv...
1238
1239
1240
  			return;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
  	if (rt && lifetime == 0) {
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1242
  		ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243
1244
  		rt = NULL;
  	}
f2a762d8a   Ben Greear   ipv6: Add more de...
1245
1246
1247
  	ND_PRINTK(3, info, "RA: rt: %p  lifetime: %d, for dev: %s
  ",
  		  rt, lifetime, skb->dev->name);
63159f29b   Ian Morris   ipv6: coding styl...
1248
  	if (!rt && lifetime) {
f2a762d8a   Ben Greear   ipv6: Add more de...
1249
1250
  		ND_PRINTK(3, info, "RA: adding default router
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1252
  		rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
63159f29b   Ian Morris   ipv6: coding styl...
1253
  		if (!rt) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1254
1255
1256
1257
  			ND_PRINTK(0, err,
  				  "RA: %s failed to add default route
  ",
  				  __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
  			return;
  		}
eb857186e   David S. Miller   ipv6: ndisc: Conv...
1260
  		neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr);
63159f29b   Ian Morris   ipv6: coding styl...
1261
  		if (!neigh) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1262
1263
1264
1265
  			ND_PRINTK(0, err,
  				  "RA: %s got default router without neighbour
  ",
  				  __func__);
94e187c01   Amerigo Wang   ipv6: introduce i...
1266
  			ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
  			return;
  		}
  		neigh->flags |= NTF_ROUTER;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1270
  	} else if (rt) {
22441cfa0   Pedro Ribeiro   IPV6: Fix default...
1271
  		rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
1274
  	}
  
  	if (rt)
1716a9610   Gao feng   ipv6: fix problem...
1275
  		rt6_set_expires(rt, jiffies + (HZ * lifetime));
8013d1d7e   Hangbin Liu   net/ipv6: add sys...
1276
1277
1278
  	if (in6_dev->cnf.accept_ra_min_hop_limit < 256 &&
  	    ra_msg->icmph.icmp6_hop_limit) {
  		if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
6fd99094d   D.S. Ljungmark   ipv6: Don't reduc...
1279
  			in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
8013d1d7e   Hangbin Liu   net/ipv6: add sys...
1280
1281
1282
  			if (rt)
  				dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
  					       ra_msg->icmph.icmp6_hop_limit);
6fd99094d   D.S. Ljungmark   ipv6: Don't reduc...
1283
  		} else {
8013d1d7e   Hangbin Liu   net/ipv6: add sys...
1284
1285
  			ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum
  ");
6fd99094d   D.S. Ljungmark   ipv6: Don't reduc...
1286
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
  	}
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1288
  skip_defrtr:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  	/*
  	 *	Update Reachable Time and Retrans Timer
  	 */
  
  	if (in6_dev->nd_parms) {
  		unsigned long rtime = ntohl(ra_msg->retrans_timer);
  
  		if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) {
  			rtime = (rtime*HZ)/1000;
  			if (rtime < HZ/10)
  				rtime = HZ/10;
1f9248e56   Jiri Pirko   neigh: convert pa...
1300
  			NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
  			in6_dev->tstamp = jiffies;
2053aeb69   Marius Tomaschewski   ipv6: send only o...
1302
  			send_ifinfo_notify = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
1305
1306
1307
1308
1309
1310
  		}
  
  		rtime = ntohl(ra_msg->reachable_time);
  		if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) {
  			rtime = (rtime*HZ)/1000;
  
  			if (rtime < HZ/10)
  				rtime = HZ/10;
1f9248e56   Jiri Pirko   neigh: convert pa...
1311
1312
1313
1314
1315
  			if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) {
  				NEIGH_VAR_SET(in6_dev->nd_parms,
  					      BASE_REACHABLE_TIME, rtime);
  				NEIGH_VAR_SET(in6_dev->nd_parms,
  					      GC_STALETIME, 3 * rtime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316
1317
  				in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
  				in6_dev->tstamp = jiffies;
2053aeb69   Marius Tomaschewski   ipv6: send only o...
1318
  				send_ifinfo_notify = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
  			}
  		}
  	}
2053aeb69   Marius Tomaschewski   ipv6: send only o...
1322
1323
1324
1325
1326
  	/*
  	 *	Send a notify if RA changed managed/otherconf flags or timer settings
  	 */
  	if (send_ifinfo_notify)
  		inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1327
  skip_linkparms:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
1332
  	/*
  	 *	Process options.
  	 */
  
  	if (!neigh)
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1333
  		neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
1338
1339
1340
  				       skb->dev, 1);
  	if (neigh) {
  		u8 *lladdr = NULL;
  		if (ndopts.nd_opts_src_lladdr) {
  			lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
  						     skb->dev);
  			if (!lladdr) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1341
1342
1343
  				ND_PRINTK(2, warn,
  					  "RA: invalid link-layer address length
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
  				goto out;
  			}
  		}
f997c55c1   Alexander Aring   ipv6: introduce n...
1347
  		ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
f997c55c1   Alexander Aring   ipv6: introduce n...
1351
1352
  			     NEIGH_UPDATE_F_ISROUTER,
  			     NDISC_ROUTER_ADVERTISEMENT, &ndopts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
  	}
f2a762d8a   Ben Greear   ipv6: Add more de...
1354
1355
1356
1357
1358
  	if (!ipv6_accept_ra(in6_dev)) {
  		ND_PRINTK(2, info,
  			  "RA: %s, accept_ra is false for dev: %s
  ",
  			  __func__, skb->dev->name);
31ce8c71a   David Ward   ipv6: Update Neig...
1359
  		goto out;
f2a762d8a   Ben Greear   ipv6: Add more de...
1360
  	}
31ce8c71a   David Ward   ipv6: Update Neig...
1361

70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1362
  #ifdef CONFIG_IPV6_ROUTE_INFO
b64288171   Li RongQing   ipv6: fix the che...
1363
1364
  	if (!in6_dev->cnf.accept_ra_from_local &&
  	    ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
c1a9a291c   Hannes Frederic Sowa   ipv6: honor ifind...
1365
  			  in6_dev->dev, 0)) {
f2a762d8a   Ben Greear   ipv6: Add more de...
1366
  		ND_PRINTK(2, info,
d93331965   Ben Greear   ipv6: Allow accep...
1367
1368
1369
  			  "RA from local address detected on dev: %s: router info ignored.
  ",
  			  skb->dev->name);
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1370
  		goto skip_routeinfo;
f2a762d8a   Ben Greear   ipv6: Add more de...
1371
  	}
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1372

09c884d4c   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1373
  	if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1374
1375
1376
1377
  		struct nd_opt_hdr *p;
  		for (p = ndopts.nd_opts_ri;
  		     p;
  		     p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
6294e0007   YOSHIFUJI Hideaki   [IPV6] NDISC: Ign...
1378
1379
1380
1381
1382
1383
  			struct route_info *ri = (struct route_info *)p;
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
  			if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
  			    ri->prefix_len == 0)
  				continue;
  #endif
30e56918d   Duan Jiong   ipv6: judge the a...
1384
1385
1386
  			if (ri->prefix_len == 0 &&
  			    !in6_dev->cnf.accept_ra_defrtr)
  				continue;
6294e0007   YOSHIFUJI Hideaki   [IPV6] NDISC: Ign...
1387
  			if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
09c884d4c   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1388
  				continue;
67ba4152e   Ian Morris   ipv6: White-space...
1389
  			rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1390
  				      &ipv6_hdr(skb)->saddr);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1391
1392
  		}
  	}
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1393
1394
  
  skip_routeinfo:
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1395
  #endif
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1396
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1397
  	/* skip link-specific ndopts from interior routers */
f2a762d8a   Ben Greear   ipv6: Add more de...
1398
1399
1400
1401
1402
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) {
  		ND_PRINTK(2, info,
  			  "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s
  ",
  			  __func__, skb->dev->name);
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1403
  		goto out;
f2a762d8a   Ben Greear   ipv6: Add more de...
1404
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1405
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1406

c4fd30eb1   YOSHIFUJI Hideaki   [IPV6]: ADDRCONF:...
1407
  	if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
1411
  		struct nd_opt_hdr *p;
  		for (p = ndopts.nd_opts_pi;
  		     p;
  		     p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
e6bff995f   Neil Horman   ipv6: Check RA fo...
1412
1413
1414
  			addrconf_prefix_rcv(skb->dev, (u8 *)p,
  					    (p->nd_opt_len) << 3,
  					    ndopts.nd_opts_src_lladdr != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
  		}
  	}
c2943f145   Harout Hedeshian   net: ipv6: Add sy...
1417
  	if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) {
e69a4adc6   Al Viro   [IPV6]: Misc endi...
1418
  		__be32 n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  		u32 mtu;
67ba4152e   Ian Morris   ipv6: White-space...
1420
  		memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
e69a4adc6   Al Viro   [IPV6]: Misc endi...
1421
  		mtu = ntohl(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
  
  		if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1424
1425
  			ND_PRINTK(2, warn, "RA: invalid mtu: %d
  ", mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
1428
1429
  		} else if (in6_dev->cnf.mtu6 != mtu) {
  			in6_dev->cnf.mtu6 = mtu;
  
  			if (rt)
defb3519a   David S. Miller   net: Abstract awa...
1430
  				dst_metric_set(&rt->dst, RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
  
  			rt6_mtu_change(skb->dev, mtu);
  		}
  	}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1435

31910575a   Pierre Ynard   [IPv6]: Export us...
1436
  	if (ndopts.nd_useropts) {
61cf46ad5   YOSHIFUJI Hideaki   [IPV6] NDISC: Spa...
1437
1438
1439
  		struct nd_opt_hdr *p;
  		for (p = ndopts.nd_useropts;
  		     p;
f997c55c1   Alexander Aring   ipv6: introduce n...
1440
1441
  		     p = ndisc_next_useropt(skb->dev, p,
  					    ndopts.nd_useropts_end)) {
61cf46ad5   YOSHIFUJI Hideaki   [IPV6] NDISC: Spa...
1442
  			ndisc_ra_useropt(skb, p);
31910575a   Pierre Ynard   [IPv6]: Export us...
1443
1444
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
  	if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1446
1447
  		ND_PRINTK(2, warn, "RA: invalid RA options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
  	}
  out:
94e187c01   Amerigo Wang   ipv6: introduce i...
1450
  	ip6_rt_put(rt);
eb857186e   David S. Miller   ipv6: ndisc: Conv...
1451
  	if (neigh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
  		neigh_release(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
1454
1455
1456
  }
  
  static void ndisc_redirect_rcv(struct sk_buff *skb)
  {
093d04d42   Duan Jiong   ipv6: Change skb-...
1457
1458
1459
  	u8 *hdr;
  	struct ndisc_options ndopts;
  	struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
29a3cad5c   Simon Horman   ipv6: Correct com...
1460
  	u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
093d04d42   Duan Jiong   ipv6: Change skb-...
1461
  				    offsetof(struct rd_msg, opt));
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1462
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1463
1464
1465
  	switch (skb->ndisc_nodetype) {
  	case NDISC_NODETYPE_HOST:
  	case NDISC_NODETYPE_NODEFAULT:
675418d51   Joe Perches   net: ipv6: ndisc:...
1466
1467
1468
  		ND_PRINTK(2, warn,
  			  "Redirect: from host or unauthorized router
  ");
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1469
1470
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1471
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1472

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1473
  	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1474
1475
1476
  		ND_PRINTK(2, warn,
  			  "Redirect: source address is not link-local
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477
1478
  		return;
  	}
f997c55c1   Alexander Aring   ipv6: introduce n...
1479
  	if (!ndisc_parse_options(skb->dev, msg->opt, ndoptlen, &ndopts))
093d04d42   Duan Jiong   ipv6: Change skb-...
1480
  		return;
c92a59eca   Duan Jiong   ipv6: handle Redi...
1481
  	if (!ndopts.nd_opts_rh) {
b55b76b22   Duan Jiong   ipv6:introduce fu...
1482
1483
  		ip6_redirect_no_header(skb, dev_net(skb->dev),
  					skb->dev->ifindex, 0);
093d04d42   Duan Jiong   ipv6: Change skb-...
1484
  		return;
c92a59eca   Duan Jiong   ipv6: handle Redi...
1485
  	}
093d04d42   Duan Jiong   ipv6: Change skb-...
1486
1487
1488
1489
1490
  
  	hdr = (u8 *)ndopts.nd_opts_rh;
  	hdr += 8;
  	if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
  		return;
b94f1c090   David S. Miller   ipv6: Use icmpv6_...
1491
  	icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1492
  }
5f5a01156   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make ndisc...
1493
1494
1495
  static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
  					   struct sk_buff *orig_skb,
  					   int rd_len)
9c86dafe9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
1496
  {
5f5a01156   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make ndisc...
1497
  	u8 *opt = skb_put(skb, rd_len);
9c86dafe9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
1498
1499
1500
1501
1502
1503
  	memset(opt, 0, 8);
  	*(opt++) = ND_OPT_REDIRECT_HDR;
  	*(opt++) = (rd_len >> 3);
  	opt += 6;
  
  	memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
9c86dafe9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
1504
  }
4991969a1   David S. Miller   ipv6: Remove neig...
1505
  void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
  {
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1507
  	struct net_device *dev = skb->dev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1508
  	struct net *net = dev_net(dev);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1509
  	struct sock *sk = net->ipv6.ndisc_sk;
2ce135761   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Calculate ...
1510
  	int optlen = 0;
fbfe95a42   David S. Miller   inet: Create and ...
1511
  	struct inet_peer *peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
  	struct sk_buff *buff;
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
1513
  	struct rd_msg *msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
  	struct in6_addr saddr_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
  	struct rt6_info *rt;
  	struct dst_entry *dst;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1517
  	struct flowi6 fl6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
  	int rd_len;
f997c55c1   Alexander Aring   ipv6: introduce n...
1519
1520
  	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL,
  	   ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL;
1d861aa4b   David S. Miller   inet: Minimize us...
1521
  	bool ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522

95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
1523
  	if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1524
1525
1526
  		ND_PRINTK(2, warn, "Redirect: no link-local address on %s
  ",
  			  dev->name);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1527
1528
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1530
  	if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
bf0b48dfc   Brian Haley   [IPv6]: Fix ICMPv...
1531
  	    ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1532
1533
1534
  		ND_PRINTK(2, warn,
  			  "Redirect: target address is not link-local unicast
  ");
29556526b   Li Yewang   [IPV6]: fix BUG o...
1535
1536
  		return;
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
1537
  	icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
e0d56fdd7   David Ahern   net: l3mdev: remo...
1538
  			 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539

4c9483b2f   David S. Miller   ipv6: Convert to ...
1540
  	dst = ip6_route_output(net, NULL, &fl6);
5095d64db   RongQing.Li   ipv6: ip6_route_o...
1541
1542
  	if (dst->error) {
  		dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
  		return;
5095d64db   RongQing.Li   ipv6: ip6_route_o...
1544
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
1545
  	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
452edd598   David S. Miller   xfrm: Return dst ...
1546
  	if (IS_ERR(dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
1549
1550
1551
  
  	rt = (struct rt6_info *) dst;
  
  	if (rt->rt6i_flags & RTF_GATEWAY) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1552
1553
1554
  		ND_PRINTK(2, warn,
  			  "Redirect: destination is not a neighbour
  ");
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1555
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  	}
fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
1557
  	peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1);
1d861aa4b   David S. Miller   inet: Minimize us...
1558
1559
1560
1561
  	ret = inet_peer_xrlim_allow(peer, 1*HZ);
  	if (peer)
  		inet_putpeer(peer);
  	if (!ret)
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1562
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
1564
  
  	if (dev->addr_len) {
4991969a1   David S. Miller   ipv6: Remove neig...
1565
1566
  		struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);
  		if (!neigh) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1567
1568
1569
  			ND_PRINTK(2, warn,
  				  "Redirect: no neigh for target address
  ");
4991969a1   David S. Miller   ipv6: Remove neig...
1570
1571
  			goto release;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
1574
1575
1576
  		read_lock_bh(&neigh->lock);
  		if (neigh->nud_state & NUD_VALID) {
  			memcpy(ha_buf, neigh->ha, dev->addr_len);
  			read_unlock_bh(&neigh->lock);
  			ha = ha_buf;
f997c55c1   Alexander Aring   ipv6: introduce n...
1577
1578
1579
  			optlen += ndisc_redirect_opt_addr_space(dev, neigh,
  								ops_data_buf,
  								&ops_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
  		} else
  			read_unlock_bh(&neigh->lock);
4991969a1   David S. Miller   ipv6: Remove neig...
1582
1583
  
  		neigh_release(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
1586
  	}
  
  	rd_len = min_t(unsigned int,
2ce135761   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Calculate ...
1587
1588
  		       IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
  		       skb->len + 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  	rd_len &= ~0x7;
2ce135761   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Calculate ...
1590
  	optlen += rd_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591

2ce135761   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Calculate ...
1592
  	buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
de09334b9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
1593
  	if (!buff)
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1594
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595

4d5c152e8   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use compou...
1596
1597
1598
1599
1600
1601
1602
1603
  	msg = (struct rd_msg *)skb_put(buff, sizeof(*msg));
  	*msg = (struct rd_msg) {
  		.icmph = {
  			.icmp6_type = NDISC_REDIRECT,
  		},
  		.target = *target,
  		.dest = ipv6_hdr(skb)->daddr,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
1608
1609
  	/*
  	 *	include target_address option
  	 */
  
  	if (ha)
f997c55c1   Alexander Aring   ipv6: introduce n...
1610
  		ndisc_fill_redirect_addr_option(buff, ha, ops_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
1613
1614
  
  	/*
  	 *	build redirect option and copy skb over to the new packet.
  	 */
9c86dafe9   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Introduce ...
1615
  	if (rd_len)
5f5a01156   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Make ndisc...
1616
  		ndisc_fill_redirect_hdr_option(buff, skb, rd_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617

adf30907d   Eric Dumazet   net: skb->dst acc...
1618
  	skb_dst_set(buff, dst);
f4de84c64   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use ndisc_...
1619
  	ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf);
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1620
1621
1622
1623
  	return;
  
  release:
  	dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
1626
1627
  }
  
  static void pndisc_redo(struct sk_buff *skb)
  {
140e26fcd   YOSHIFUJI Hideaki   [IPV6]: Fix NS ha...
1628
  	ndisc_recv_ns(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
  	kfree_skb(skb);
  }
b800c3b96   Hannes Frederic Sowa   ipv6: drop fragme...
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
  static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
  {
  	struct inet6_dev *idev = __in6_dev_get(skb->dev);
  
  	if (!idev)
  		return true;
  	if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
  	    idev->cnf.suppress_frag_ndisc) {
  		net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.
  ");
  		return true;
  	}
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
1646
1647
  int ndisc_rcv(struct sk_buff *skb)
  {
  	struct nd_msg *msg;
b800c3b96   Hannes Frederic Sowa   ipv6: drop fragme...
1648
1649
  	if (ndisc_suppress_frag_ndisc(skb))
  		return 0;
6bce6b4e1   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use skb_li...
1650
  	if (skb_linearize(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
  		return 0;
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1652
  	msg = (struct nd_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653

9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1654
  	__skb_push(skb, skb->data - skb_transport_header(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1656
  	if (ipv6_hdr(skb)->hop_limit != 255) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1657
1658
1659
  		ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d
  ",
  			  ipv6_hdr(skb)->hop_limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660
1661
1662
1663
  		return 0;
  	}
  
  	if (msg->icmph.icmp6_code != 0) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1664
1665
1666
  		ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d
  ",
  			  msg->icmph.icmp6_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
1668
  		return 0;
  	}
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
1669
  	memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  	switch (msg->icmph.icmp6_type) {
  	case NDISC_NEIGHBOUR_SOLICITATION:
  		ndisc_recv_ns(skb);
  		break;
  
  	case NDISC_NEIGHBOUR_ADVERTISEMENT:
  		ndisc_recv_na(skb);
  		break;
  
  	case NDISC_ROUTER_SOLICITATION:
  		ndisc_recv_rs(skb);
  		break;
  
  	case NDISC_ROUTER_ADVERTISEMENT:
  		ndisc_router_discovery(skb);
  		break;
  
  	case NDISC_REDIRECT:
  		ndisc_redirect_rcv(skb);
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1690
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
1692
1693
1694
1695
1696
  
  	return 0;
  }
  
  static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
351638e7d   Jiri Pirko   net: pass info st...
1697
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
c8507fb23   Eric Dumazet   ipv6: flush nd ca...
1698
  	struct netdev_notifier_change_info *change_info;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1699
  	struct net *net = dev_net(dev);
5cb04436e   Hannes Frederic Sowa   ipv6: add knob to...
1700
  	struct inet6_dev *idev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
1702
1703
1704
  
  	switch (event) {
  	case NETDEV_CHANGEADDR:
  		neigh_changeaddr(&nd_tbl, dev);
2ac3ac8f8   Michal Kubeček   ipv6: prevent fib...
1705
  		fib6_run_gc(0, net, false);
5cb04436e   Hannes Frederic Sowa   ipv6: add knob to...
1706
1707
1708
1709
1710
1711
  		idev = in6_dev_get(dev);
  		if (!idev)
  			break;
  		if (idev->cnf.ndisc_notify)
  			ndisc_send_unsol_na(dev);
  		in6_dev_put(idev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
  		break;
c8507fb23   Eric Dumazet   ipv6: flush nd ca...
1713
1714
1715
1716
1717
  	case NETDEV_CHANGE:
  		change_info = ptr;
  		if (change_info->flags_changed & IFF_NOARP)
  			neigh_changeaddr(&nd_tbl, dev);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1718
1719
  	case NETDEV_DOWN:
  		neigh_ifdown(&nd_tbl, dev);
2ac3ac8f8   Michal Kubeček   ipv6: prevent fib...
1720
  		fib6_run_gc(0, net, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
  		break;
f47b94646   Ben Hutchings   ipv6: Send unsoli...
1722
1723
1724
  	case NETDEV_NOTIFY_PEERS:
  		ndisc_send_unsol_na(dev);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  	default:
  		break;
  	}
  
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block ndisc_netdev_notifier = {
  	.notifier_call = ndisc_netdev_event,
  };
  
  #ifdef CONFIG_SYSCTL
  static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl,
  					 const char *func, const char *dev_name)
  {
  	static char warncomm[TASK_COMM_LEN];
  	static int warned;
  	if (strcmp(warncomm, current->comm) && warned < 5) {
  		strcpy(warncomm, current->comm);
f32138319   Joe Perches   net: ipv6: Standa...
1744
1745
  		pr_warn("process `%s' is using deprecated sysctl (%s) net.ipv6.neigh.%s.%s - use net.ipv6.neigh.%s.%s_ms instead
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746
1747
1748
1749
1750
1751
  			warncomm, func,
  			dev_name, ctl->procname,
  			dev_name, ctl->procname);
  		warned++;
  	}
  }
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1752
  int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
  {
  	struct net_device *dev = ctl->extra1;
  	struct inet6_dev *idev;
  	int ret;
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1757
1758
  	if ((strcmp(ctl->procname, "retrans_time") == 0) ||
  	    (strcmp(ctl->procname, "base_reachable_time") == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
  		ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1760
  	if (strcmp(ctl->procname, "retrans_time") == 0)
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
1761
  		ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1762
1763
  
  	else if (strcmp(ctl->procname, "base_reachable_time") == 0)
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
1764
1765
  		ret = neigh_proc_dointvec_jiffies(ctl, write,
  						  buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1766
1767
  
  	else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
ad02ac145   YOSHIFUJI Hideaki   [IPV6] NDISC: Fix...
1768
  		 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
1769
1770
  		ret = neigh_proc_dointvec_ms_jiffies(ctl, write,
  						     buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1771
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
  		ret = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
  
  	if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
1f9248e56   Jiri Pirko   neigh: convert pa...
1775
1776
1777
  		if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME))
  			idev->nd_parms->reachable_time =
  					neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
1779
1780
1781
1782
1783
  		idev->tstamp = jiffies;
  		inet6_ifinfo_notify(RTM_NEWLINK, idev);
  		in6_dev_put(idev);
  	}
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
  
  #endif
2c8c1e729   Alexey Dobriyan   net: spread __net...
1786
  static int __net_init ndisc_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1787
1788
1789
  {
  	struct ipv6_pinfo *np;
  	struct sock *sk;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1790
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1791

1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1792
1793
  	err = inet_ctl_sock_create(&sk, PF_INET6,
  				   SOCK_RAW, IPPROTO_ICMPV6, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
  	if (err < 0) {
675418d51   Joe Perches   net: ipv6: ndisc:...
1795
1796
1797
1798
  		ND_PRINTK(0, err,
  			  "NDISC: Failed to initialize the control socket (err %d)
  ",
  			  err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
1800
  		return err;
  	}
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1801
  	net->ipv6.ndisc_sk = sk;
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1802

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  	np = inet6_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
1806
  	np->hop_limit = 255;
  	/* Do not loopback ndisc messages */
  	np->mc_loop = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807

1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1808
1809
  	return 0;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1810
  static void __net_exit ndisc_net_exit(struct net *net)
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1811
  {
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1812
  	inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
  }
  
  static struct pernet_operations ndisc_net_ops = {
  	.init = ndisc_net_init,
  	.exit = ndisc_net_exit,
  };
  
  int __init ndisc_init(void)
  {
  	int err;
  
  	err = register_pernet_subsys(&ndisc_net_ops);
  	if (err)
  		return err;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1827
1828
1829
  	/*
  	 * Initialize the neighbour table
  	 */
d7480fd3b   WANG Cong   neigh: remove dyn...
1830
  	neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
  
  #ifdef CONFIG_SYSCTL
73af614ae   Jiri Pirko   neigh: use tbl->f...
1833
  	err = neigh_sysctl_register(NULL, &nd_tbl.parms,
56ec0fb10   Himangi Saraogi   neigh: remove exc...
1834
  				    ndisc_ifinfo_sysctl_change);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1835
1836
  	if (err)
  		goto out_unregister_pernet;
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1837
  out:
bcd081a3a   Fabio Estevam   net: ipv6: ndisc:...
1838
  #endif
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1839
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840

1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1841
  #ifdef CONFIG_SYSCTL
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1842
  out_unregister_pernet:
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1843
1844
  	unregister_pernet_subsys(&ndisc_net_ops);
  	goto out;
2c861cc65   Michal Kubeček   ipv6: don't call ...
1845
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1846
  }
2c861cc65   Michal Kubeček   ipv6: don't call ...
1847
1848
1849
1850
1851
1852
  int __init ndisc_late_init(void)
  {
  	return register_netdevice_notifier(&ndisc_netdev_notifier);
  }
  
  void ndisc_late_cleanup(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
  {
36f73d0c3   Dmitry Mishin   [IPV6]: Add ndisc...
1854
  	unregister_netdevice_notifier(&ndisc_netdev_notifier);
2c861cc65   Michal Kubeček   ipv6: don't call ...
1855
1856
1857
1858
  }
  
  void ndisc_cleanup(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
  #ifdef CONFIG_SYSCTL
  	neigh_sysctl_unregister(&nd_tbl.parms);
  #endif
d7480fd3b   WANG Cong   neigh: remove dyn...
1862
  	neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1863
  	unregister_pernet_subsys(&ndisc_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
  }