Blame view

net/ipv6/ndisc.c 45.9 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:
   *
31910575a   Pierre Ynard   [IPv6]: Export us...
18
19
   *	Pierre Ynard			:	export userland ND options
   *						through netlink (RDNSS support)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
   *	Lars Fenneberg			:	fixed MTU setting on receipt
   *						of an RA.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
   *	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
   */
  
  /* Set to 3 to get tracing... */
  #define ND_DEBUG 1
  
  #define ND_PRINTK(fmt, args...) do { if (net_ratelimit()) { printk(fmt, ## args); } } while(0)
  #define ND_NOPRINTK(x...) do { ; } while(0)
  #define ND_PRINTK0 ND_PRINTK
  #define ND_PRINTK1 ND_NOPRINTK
  #define ND_PRINTK2 ND_NOPRINTK
  #define ND_PRINTK3 ND_NOPRINTK
  #if ND_DEBUG >= 1
  #undef ND_PRINTK1
  #define ND_PRINTK1 ND_PRINTK
  #endif
  #if ND_DEBUG >= 2
  #undef ND_PRINTK2
  #define ND_PRINTK2 ND_PRINTK
  #endif
  #if ND_DEBUG >= 3
  #undef ND_PRINTK3
  #define ND_PRINTK3 ND_PRINTK
  #endif
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
  #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: ...
62
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
1823730fb   Thomas Graf   [IPv4]: Move inte...
66
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  #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...
81
82
  #include <net/netlink.h>
  #include <linux/rtnetlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
  #include <net/flow.h>
  #include <net/ip6_checksum.h>
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
85
  #include <net/inet_common.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
  #include <linux/proc_fs.h>
  
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv6.h>
d6bf78171   Eric Dumazet   net neigh: RCU co...
90
91
  static u32 ndisc_hash(const void *pkey,
  		      const struct net_device *dev,
2c2aba6c5   David S. Miller   ipv6: Use univers...
92
  		      __u32 *hash_rnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
  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...
99
  static const struct neigh_ops ndisc_generic_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
  	.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
105
  };
89d69d2b7   Stephen Hemminger   net: make neigh_o...
106
  static const struct neigh_ops ndisc_hh_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
  	.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
112
  };
89d69d2b7   Stephen Hemminger   net: make neigh_o...
113
  static const struct neigh_ops ndisc_direct_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	.family =		AF_INET6,
8f40b161d   David S. Miller   neigh: Pass neigh...
115
116
  	.output =		neigh_direct_output,
  	.connected_output =	neigh_direct_output,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
  };
  
  struct neigh_table nd_tbl = {
  	.family =	AF_INET6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
  	.key_len =	sizeof(struct in6_addr),
  	.hash =		ndisc_hash,
  	.constructor =	ndisc_constructor,
  	.pconstructor =	pndisc_constructor,
  	.pdestructor =	pndisc_destructor,
  	.proxy_redo =	pndisc_redo,
  	.id =		"ndisc_cache",
  	.parms = {
b672083ed   Shan Wei   ipv6: use ND_REAC...
129
130
131
132
133
134
  		.tbl			= &nd_tbl,
  		.base_reachable_time	= ND_REACHABLE_TIME,
  		.retrans_time		= ND_RETRANS_TIMER,
  		.gc_staletime		= 60 * HZ,
  		.reachable_time		= ND_REACHABLE_TIME,
  		.delay_probe_time	= 5 * HZ,
8b5c171bb   Eric Dumazet   neigh: new unreso...
135
  		.queue_len_bytes	= 64*1024,
b672083ed   Shan Wei   ipv6: use ND_REAC...
136
137
138
139
140
  		.ucast_probes		= 3,
  		.mcast_probes		= 3,
  		.anycast_delay		= 1 * HZ,
  		.proxy_delay		= (8 * HZ) / 10,
  		.proxy_qlen		= 64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
149
  	},
  	.gc_interval =	  30 * HZ,
  	.gc_thresh1 =	 128,
  	.gc_thresh2 =	 512,
  	.gc_thresh3 =	1024,
  };
  
  /* ND options */
  struct ndisc_options {
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
150
151
152
153
154
  	struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
  #ifdef CONFIG_IPV6_ROUTE_INFO
  	struct nd_opt_hdr *nd_opts_ri;
  	struct nd_opt_hdr *nd_opts_ri_end;
  #endif
31910575a   Pierre Ynard   [IPv6]: Export us...
155
156
  	struct nd_opt_hdr *nd_useropts;
  	struct nd_opt_hdr *nd_useropts_end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  };
  
  #define nd_opts_src_lladdr	nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
  #define nd_opts_tgt_lladdr	nd_opt_array[ND_OPT_TARGET_LL_ADDR]
  #define nd_opts_pi		nd_opt_array[ND_OPT_PREFIX_INFO]
  #define nd_opts_pi_end		nd_opt_array[__ND_OPT_PREFIX_INFO_END]
  #define nd_opts_rh		nd_opt_array[ND_OPT_REDIRECT_HDR]
  #define nd_opts_mtu		nd_opt_array[ND_OPT_MTU]
  
  #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
  
  /*
   * Return the padding between the option length and the start of the
   * link addr.  Currently only IP-over-InfiniBand needs this, although
   * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
   * also need a pad of 2.
   */
  static int ndisc_addr_option_pad(unsigned short type)
  {
  	switch (type) {
  	case ARPHRD_INFINIBAND: return 2;
  	default:                return 0;
  	}
  }
  
  static inline int ndisc_opt_addr_space(struct net_device *dev)
  {
  	return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
  }
  
  static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
  				  unsigned short addr_type)
  {
  	int space = NDISC_OPT_SPACE(data_len);
  	int pad   = ndisc_addr_option_pad(addr_type);
  
  	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;
  	if ((space -= data_len) > 0)
  		memset(opt, 0, space);
  	return opt + space;
  }
  
  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);
  	} while(cur < end && cur->nd_opt_type != type);
a02cec215   Eric Dumazet   net: return opera...
218
  	return cur <= end && cur->nd_opt_type == type ? cur : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  }
31910575a   Pierre Ynard   [IPv6]: Export us...
220
221
  static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
  {
a02cec215   Eric Dumazet   net: return opera...
222
  	return opt->nd_opt_type == ND_OPT_RDNSS;
31910575a   Pierre Ynard   [IPv6]: Export us...
223
224
225
226
227
228
229
230
231
232
  }
  
  static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
  					     struct nd_opt_hdr *end)
  {
  	if (!cur || !end || cur >= end)
  		return NULL;
  	do {
  		cur = ((void *)cur) + (cur->nd_opt_len << 3);
  	} while(cur < end && !ndisc_is_useropt(cur));
a02cec215   Eric Dumazet   net: return opera...
233
  	return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
31910575a   Pierre Ynard   [IPv6]: Export us...
234
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
  						 struct ndisc_options *ndopts)
  {
  	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;
  		switch (nd_opt->nd_opt_type) {
  		case ND_OPT_SOURCE_LL_ADDR:
  		case ND_OPT_TARGET_LL_ADDR:
  		case ND_OPT_MTU:
  		case ND_OPT_REDIRECT_HDR:
  			if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
  				ND_PRINTK2(KERN_WARNING
  					   "%s(): duplicated ND6 option found: type=%d
  ",
0dc47877a   Harvey Harrison   net: replace rema...
259
  					   __func__,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
265
266
  					   nd_opt->nd_opt_type);
  			} 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...
267
  			if (!ndopts->nd_opt_array[nd_opt->nd_opt_type])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
  			break;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
270
271
272
273
274
275
276
  #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
277
  		default:
31910575a   Pierre Ynard   [IPv6]: Export us...
278
279
280
281
282
283
284
285
286
287
288
289
290
  			if (ndisc_is_useropt(nd_opt)) {
  				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.
  				 */
  				ND_PRINTK2(KERN_NOTICE
  					   "%s(): ignored unsupported option; type=%d, len=%d
  ",
0dc47877a   Harvey Harrison   net: replace rema...
291
  					   __func__,
31910575a   Pierre Ynard   [IPv6]: Export us...
292
293
  					   nd_opt->nd_opt_type, nd_opt->nd_opt_len);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  		}
  		opt_len -= l;
  		nd_opt = ((void *)nd_opt) + l;
  	}
  	return ndopts;
  }
  
  static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
  				      struct net_device *dev)
  {
  	u8 *lladdr = (u8 *)(p + 1);
  	int lladdrlen = p->nd_opt_len << 3;
  	int prepad = ndisc_addr_option_pad(dev->type);
  	if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
  		return NULL;
a02cec215   Eric Dumazet   net: return opera...
309
  	return lladdr + prepad;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  }
b71d1d426   Eric Dumazet   inet: constify ip...
311
  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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  {
  	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;
  	case ARPHRD_IEEE802_TR:
  		ipv6_tr_mc_map(addr,buf);
  		return 0;
  	case ARPHRD_ARCNET:
  		ipv6_arcnet_mc_map(addr, buf);
  		return 0;
  	case ARPHRD_INFINIBAND:
a9e527e3f   Rolf Manderscheid   IPoIB: improve IP...
326
  		ipv6_ib_mc_map(addr, dev->broadcast, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  		return 0;
93ca3bb5d   Timo Teräs   net: gre: provide...
328
329
  	case ARPHRD_IPGRE:
  		return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
336
337
  	default:
  		if (dir) {
  			memcpy(buf, dev->broadcast, dev->addr_len);
  			return 0;
  		}
  	}
  	return -EINVAL;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
338
  EXPORT_SYMBOL(ndisc_mc_map);
d6bf78171   Eric Dumazet   net neigh: RCU co...
339
340
  static u32 ndisc_hash(const void *pkey,
  		      const struct net_device *dev,
2c2aba6c5   David S. Miller   ipv6: Use univers...
341
  		      __u32 *hash_rnd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  {
2c2aba6c5   David S. Miller   ipv6: Use univers...
343
  	return ndisc_hashfn(pkey, dev, hash_rnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
  }
  
  static int ndisc_constructor(struct neighbour *neigh)
  {
  	struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
  	struct net_device *dev = neigh->dev;
  	struct inet6_dev *in6_dev;
  	struct neigh_parms *parms;
  	int is_multicast = ipv6_addr_is_multicast(addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  	in6_dev = in6_dev_get(dev);
  	if (in6_dev == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
360
  		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
361
362
  
  	neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
363
  	if (!dev->header_ops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  		neigh->nud_state = NUD_NOARP;
  		neigh->ops = &ndisc_direct_ops;
8f40b161d   David S. Miller   neigh: Pass neigh...
366
  		neigh->output = neigh_direct_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
376
377
378
379
  	} 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...
380
  		if (dev->header_ops->cache)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  			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)
  {
  	struct in6_addr *addr = (struct in6_addr*)&n->key;
  	struct in6_addr maddr;
  	struct net_device *dev = n->dev;
  
  	if (dev == NULL || __in6_dev_get(dev) == NULL)
  		return -EINVAL;
  	addrconf_addr_solict_mult(addr, &maddr);
  	ipv6_dev_mc_inc(dev, &maddr);
  	return 0;
  }
  
  static void pndisc_destructor(struct pneigh_entry *n)
  {
  	struct in6_addr *addr = (struct in6_addr*)&n->key;
  	struct in6_addr maddr;
  	struct net_device *dev = n->dev;
  
  	if (dev == NULL || __in6_dev_get(dev) == NULL)
  		return;
  	addrconf_addr_solict_mult(addr, &maddr);
  	ipv6_dev_mc_dec(dev, &maddr);
  }
305d552ac   Brian Haley   bonding: send IPv...
417
418
419
420
421
422
  struct sk_buff *ndisc_build_skb(struct net_device *dev,
  				const struct in6_addr *daddr,
  				const struct in6_addr *saddr,
  				struct icmp6hdr *icmp6h,
  				const struct in6_addr *target,
  				int llinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
424
  	struct net *net = dev_net(dev);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
425
  	struct sock *sk = net->ipv6.ndisc_sk;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
426
  	struct sk_buff *skb;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
427
  	struct icmp6hdr *hdr;
a7ae19922   Herbert Xu   ipv6: Remove all ...
428
429
  	int hlen = LL_RESERVED_SPACE(dev);
  	int tlen = dev->needed_tailroom;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
430
  	int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  	int err;
305d552ac   Brian Haley   bonding: send IPv...
432
  	u8 *opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433

e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
434
435
436
437
438
439
  	if (!dev->addr_len)
  		llinfo = 0;
  
  	len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
  	if (llinfo)
  		len += ndisc_opt_addr_space(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440

d54a81d34   David S. Miller   [IPV6] NDISC: Cal...
441
442
  	skb = sock_alloc_send_skb(sk,
  				  (MAX_HEADER + sizeof(struct ipv6hdr) +
a7ae19922   Herbert Xu   ipv6: Remove all ...
443
  				   len + hlen + tlen),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  				  1, &err);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
445
  	if (!skb) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  		ND_PRINTK0(KERN_ERR
dae9de8e1   Brian Haley   IPv6: Print error...
447
448
449
  			   "ICMPv6 ND: %s() failed to allocate an skb, err=%d.
  ",
  			   __func__, err);
305d552ac   Brian Haley   bonding: send IPv...
450
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	}
a7ae19922   Herbert Xu   ipv6: Remove all ...
452
  	skb_reserve(skb, hlen);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
453
  	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
455
  	skb->transport_header = skb->tail;
d10ba34b0   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
456
  	skb_put(skb, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457

e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
458
459
  	hdr = (struct icmp6hdr *)skb_transport_header(skb);
  	memcpy(hdr, icmp6h, sizeof(*hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460

e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
461
462
  	opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
  	if (target) {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
463
  		*(struct in6_addr *)opt = *target;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
464
465
  		opt += sizeof(*target);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466

e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
467
468
  	if (llinfo)
  		ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  				       dev->addr_len, dev->type);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
470
471
  	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
  					   IPPROTO_ICMPV6,
07f0757a6   Joe Perches   include/net net/ ...
472
  					   csum_partial(hdr,
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
473
  							len, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474

305d552ac   Brian Haley   bonding: send IPv...
475
476
477
478
479
480
481
482
483
484
485
486
  	return skb;
  }
  
  EXPORT_SYMBOL(ndisc_build_skb);
  
  void ndisc_send_skb(struct sk_buff *skb,
  		    struct net_device *dev,
  		    struct neighbour *neigh,
  		    const struct in6_addr *daddr,
  		    const struct in6_addr *saddr,
  		    struct icmp6hdr *icmp6h)
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
487
  	struct flowi6 fl6;
305d552ac   Brian Haley   bonding: send IPv...
488
489
490
491
492
493
494
495
  	struct dst_entry *dst;
  	struct net *net = dev_net(dev);
  	struct sock *sk = net->ipv6.ndisc_sk;
  	struct inet6_dev *idev;
  	int err;
  	u8 type;
  
  	type = icmp6h->icmp6_type;
4c9483b2f   David S. Miller   ipv6: Convert to ...
496
  	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
87a115783   David S. Miller   ipv6: Move xfrm_l...
497
  	dst = icmp6_dst_alloc(dev, neigh, &fl6);
452edd598   David S. Miller   xfrm: Return dst ...
498
  	if (IS_ERR(dst)) {
305d552ac   Brian Haley   bonding: send IPv...
499
500
501
  		kfree_skb(skb);
  		return;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
502
  	skb_dst_set(skb, dst);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
503

cfdf76474   Eric Dumazet   ipv6: some RCU co...
504
505
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
edf391ff1   Neil Horman   snmp: add missing...
506
  	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
507

b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
508
  	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
509
  		      dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  	if (!err) {
5c5d244bd   Denis V. Lunev   ipv6: added net a...
511
  		ICMP6MSGOUT_INC_STATS(net, idev, type);
a862f6a6d   Denis V. Lunev   ipv6: added net a...
512
  		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  	}
cfdf76474   Eric Dumazet   ipv6: some RCU co...
514
  	rcu_read_unlock();
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
515
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

305d552ac   Brian Haley   bonding: send IPv...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  EXPORT_SYMBOL(ndisc_send_skb);
  
  /*
   *	Send a Neighbour Discover packet
   */
  static void __ndisc_send(struct net_device *dev,
  			 struct neighbour *neigh,
  			 const struct in6_addr *daddr,
  			 const struct in6_addr *saddr,
  			 struct icmp6hdr *icmp6h, const struct in6_addr *target,
  			 int llinfo)
  {
  	struct sk_buff *skb;
  
  	skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
  	if (!skb)
  		return;
  
  	ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
  }
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
537
  static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
538
539
540
  			  const struct in6_addr *daddr,
  			  const struct in6_addr *solicited_addr,
  			  int router, int solicited, int override, int inc_opt)
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
541
542
543
  {
  	struct in6_addr tmpaddr;
  	struct inet6_ifaddr *ifp;
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
544
  	const struct in6_addr *src_addr;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
545
546
547
548
549
  	struct icmp6hdr icmp6h = {
  		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
  	};
  
  	/* for anycast or proxy, solicited_addr != src_addr */
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
550
  	ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
551
552
553
554
  	if (ifp) {
  		src_addr = solicited_addr;
  		if (ifp->flags & IFA_F_OPTIMISTIC)
  			override = 0;
9f888160b   stephen hemminger   ipv6: fix NULL re...
555
  		inc_opt |= ifp->idev->cnf.force_tllao;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
556
557
  		in6_ifa_put(ifp);
  	} else {
191cd5825   Brian Haley   netns: Add networ...
558
  		if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
559
  				       inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
560
  				       &tmpaddr))
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
561
562
563
564
565
566
567
568
569
570
  			return;
  		src_addr = &tmpaddr;
  	}
  
  	icmp6h.icmp6_router = router;
  	icmp6h.icmp6_solicited = solicited;
  	icmp6h.icmp6_override = override;
  
  	__ndisc_send(dev, neigh, daddr, src_addr,
  		     &icmp6h, solicited_addr,
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
571
  		     inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
572
  }
f47b94646   Ben Hutchings   ipv6: Send unsoli...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  static void ndisc_send_unsol_na(struct net_device *dev)
  {
  	struct inet6_dev *idev;
  	struct inet6_ifaddr *ifa;
  	struct in6_addr mcaddr;
  
  	idev = in6_dev_get(dev);
  	if (!idev)
  		return;
  
  	read_lock_bh(&idev->lock);
  	list_for_each_entry(ifa, &idev->addr_list, if_list) {
  		addrconf_addr_solict_mult(&ifa->addr, &mcaddr);
  		ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
  			      /*router=*/ !!idev->cnf.forwarding,
  			      /*solicited=*/ false, /*override=*/ true,
  			      /*inc_opt=*/ true);
  	}
  	read_unlock_bh(&idev->lock);
  
  	in6_dev_put(idev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
596
597
  		   const struct in6_addr *solicit,
  		   const struct in6_addr *daddr, const struct in6_addr *saddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	struct in6_addr addr_buf;
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
600
601
602
  	struct icmp6hdr icmp6h = {
  		.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  
  	if (saddr == NULL) {
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
605
606
  		if (ipv6_get_lladdr(dev, &addr_buf,
  				   (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
  			return;
  		saddr = &addr_buf;
  	}
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
610
611
  	__ndisc_send(dev, neigh, daddr, saddr,
  		     &icmp6h, solicit,
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
612
  		     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  }
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
614
615
  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
616
  {
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
617
618
619
  	struct icmp6hdr icmp6h = {
  		.icmp6_type = NDISC_ROUTER_SOLICITATION,
  	};
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
620
  	int send_sllao = dev->addr_len;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
621
622
623
624
625
626
627
628
  
  #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 ...
629
  	 * suppress the inclusion of the sllao.
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
630
631
  	 */
  	if (send_sllao) {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
632
  		struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
1cab3da6b   Daniel Lezcano   [NETNS][IPV6]: in...
633
  							   dev, 1);
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
634
635
  		if (ifp) {
  			if (ifp->flags & IFA_F_OPTIMISTIC)  {
ca0435693   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
636
  				send_sllao = 0;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
637
  			}
ca0435693   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
638
  			in6_ifa_put(ifp);
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
639
640
641
642
643
  		} else {
  			send_sllao = 0;
  		}
  	}
  #endif
e1ec7842d   YOSHIFUJI Hideaki   [IPV6] NDISC: Uni...
644
645
  	__ndisc_send(dev, NULL, daddr, saddr,
  		     &icmp6h, NULL,
14878f75a   David L Stevens   [IPV6]: Add ICMPM...
646
  		     send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  }
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
648

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  
  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);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
669
  	if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
670
  		saddr = &ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
  
  	if ((probes -= neigh->parms->ucast_probes) < 0) {
  		if (!(neigh->nud_state & NUD_VALID)) {
5b095d989   Harvey Harrison   net: replace %p6 ...
674
675
  			ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: %pI6
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
676
  				   __func__, target);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
684
685
686
687
  		}
  		ndisc_send_ns(dev, neigh, target, target, saddr);
  	} else if ((probes -= neigh->parms->app_probes) < 0) {
  #ifdef CONFIG_ARPD
  		neigh_app_ns(neigh);
  #endif
  	} else {
  		addrconf_addr_solict_mult(target, &mcaddr);
  		ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
  	}
  }
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
688
689
  static int pndisc_is_router(const void *pkey,
  			    struct net_device *dev)
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
690
691
  {
  	struct pneigh_entry *n;
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
692
  	int ret = -1;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
693
694
  
  	read_lock_bh(&nd_tbl.lock);
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
695
696
697
  	n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
  	if (n)
  		ret = !!(n->flags & NTF_ROUTER);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
698
  	read_unlock_bh(&nd_tbl.lock);
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
699
  	return ret;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
700
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
  static void ndisc_recv_ns(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
703
  	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
704
705
  	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
706
  	u8 *lladdr = NULL;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
707
708
  	u32 ndoptlen = skb->tail - (skb->transport_header +
  				    offsetof(struct nd_msg, opt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
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);
  	int inc;
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
716
  	int is_router = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
  
  	if (ipv6_addr_is_multicast(&msg->target)) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
719
  		ND_PRINTK2(KERN_WARNING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  			   "ICMPv6 NS: multicast target address");
  		return;
  	}
  
  	/*
  	 * RFC2461 7.1.1:
  	 * DAD has to be destined for solicited node multicast address.
  	 */
  	if (dad &&
  	    !(daddr->s6_addr32[0] == htonl(0xff020000) &&
  	      daddr->s6_addr32[1] == htonl(0x00000000) &&
  	      daddr->s6_addr32[2] == htonl(0x00000001) &&
  	      daddr->s6_addr [12] == 0xff )) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NS: bad DAD packet (wrong destination)
  ");
  		return;
  	}
  
  	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
740
  		ND_PRINTK2(KERN_WARNING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  			   "ICMPv6 NS: invalid ND options
  ");
  		return;
  	}
  
  	if (ndopts.nd_opts_src_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
  		if (!lladdr) {
  			ND_PRINTK2(KERN_WARNING
  				   "ICMPv6 NS: invalid link-layer address length
  ");
  			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) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
761
  			ND_PRINTK2(KERN_WARNING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
765
766
767
768
  				   "ICMPv6 NS: bad DAD packet (link-layer address option)
  ");
  			return;
  		}
  	}
  
  	inc = ipv6_addr_is_multicast(daddr);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
769
  	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
770
  	if (ifp) {
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
771
772
773
774
  
  		if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
  			if (dad) {
  				if (dev->type == ARPHRD_IEEE802_TR) {
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
775
776
  					const unsigned char *sadr;
  					sadr = skb_mac_header(skb);
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  					if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
  					    sadr[9] == dev->dev_addr[1] &&
  					    sadr[10] == dev->dev_addr[2] &&
  					    sadr[11] == dev->dev_addr[3] &&
  					    sadr[12] == dev->dev_addr[4] &&
  					    sadr[13] == dev->dev_addr[5]) {
  						/* looped-back to us */
  						goto out;
  					}
  				}
  
  				/*
  				 * 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...
794
  				return;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
795
796
797
798
799
800
801
802
  			} 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
803
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
808
  		}
  
  		idev = ifp->idev;
  	} else {
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
809
  		struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
  		idev = in6_dev_get(dev);
  		if (!idev) {
  			/* XXX: count this drop? */
  			return;
  		}
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
815
  		if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
816
  		    (idev->cnf.forwarding &&
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
817
  		     (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
0736ffc04   YOSHIFUJI Hideaki   [IPV6] NEIGH: Opt...
818
  		     (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
819
  			if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
  			    skb->pkt_type != PACKET_HOST &&
  			    inc != 0 &&
  			    idev->nd_parms->proxy_delay != 0) {
  				/*
  				 * for anycast or proxy,
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
825
826
  				 * sender should delay its response
  				 * by a random time between 0 and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
833
834
835
836
837
  				 * 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...
838
839
  	if (is_router < 0)
  		is_router = !!idev->cnf.forwarding;
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
840

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  	if (dad) {
f3ee4010e   YOSHIFUJI Hideaki   [IPV6]: Define co...
842
  		ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
843
  			      is_router, 0, (ifp != NULL), 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
847
848
849
850
  		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...
851
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
  	 *	update / create cache entry
  	 *	for the source address
  	 */
  	neigh = __neigh_lookup(&nd_tbl, saddr, dev,
  			       !inc || lladdr || !dev->addr_len);
  	if (neigh)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
858
  		neigh_update(neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE);
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
861
  	if (neigh || !dev->header_ops) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
  		ndisc_send_na(dev, neigh, saddr, &msg->target,
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
863
  			      is_router,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
866
867
868
869
870
871
872
873
  			      1, (ifp != NULL && inc), inc);
  		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
874
875
876
877
  }
  
  static void ndisc_recv_na(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
878
  	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
879
880
  	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
881
  	u8 *lladdr = NULL;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
882
883
  	u32 ndoptlen = skb->tail - (skb->transport_header +
  				    offsetof(struct nd_msg, opt));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
  	struct ndisc_options ndopts;
  	struct net_device *dev = skb->dev;
  	struct inet6_ifaddr *ifp;
  	struct neighbour *neigh;
  
  	if (skb->len < sizeof(struct nd_msg)) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NA: packet too short
  ");
  		return;
  	}
  
  	if (ipv6_addr_is_multicast(&msg->target)) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NA: target address is multicast.
  ");
  		return;
  	}
  
  	if (ipv6_addr_is_multicast(daddr) &&
  	    msg->icmph.icmp6_solicited) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NA: solicited NA is multicasted.
  ");
  		return;
  	}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
910

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NS: invalid ND option
  ");
  		return;
  	}
  	if (ndopts.nd_opts_tgt_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
  		if (!lladdr) {
  			ND_PRINTK2(KERN_WARNING
  				   "ICMPv6 NA: invalid link-layer address length
  ");
  			return;
  		}
  	}
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
926
  	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
927
  	if (ifp) {
bd015928b   Daniel Walter   ipv6: ignore loop...
928
929
930
931
  		if (skb->pkt_type != PACKET_LOOPBACK
  		    && (ifp->flags & IFA_F_TENTATIVE)) {
  				addrconf_dad_failure(ifp);
  				return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
  		}
  		/* 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...
937
938
939
940
  
  		   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
941
  		 */
24fc7b86d   Jan Sembera   ipv6: silence log...
942
943
  		if (skb->pkt_type != PACKET_LOOPBACK)
  			ND_PRINTK1(KERN_WARNING
a6fa32866   Jens Rosenboom   ipv6: Log the exp...
944
945
946
  			   "ICMPv6 NA: someone advertises our address %pI6 on %s!
  ",
  			   &ifp->addr, ifp->idev->dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
953
  		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 ...
954
  		struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
  
  		if (neigh->nud_state & NUD_FAILED)
  			goto out;
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
958
959
960
961
962
963
  		/*
  		 * 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 ...
964
965
  		    net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
  		    pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
fbea49e1e   YOSHIFUJI Hideaki   [IPV6] NDISC: Add...
966
  			/* XXX: idev->cnf.prixy_ndp */
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
967
  			goto out;
fbea49e1e   YOSHIFUJI Hideaki   [IPV6] NDISC: Add...
968
  		}
5f3e6e9e1   Ville Nuorvala   [IPV6] NDISC: Avo...
969

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
972
973
974
975
976
977
978
979
980
981
982
983
  		neigh_update(neigh, lladdr,
  			     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|
  			     (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
  
  		if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
  			/*
  			 * Change: router to host
  			 */
  			struct rt6_info *rt;
  			rt = rt6_get_dflt_router(saddr, dev);
  			if (rt)
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
984
  				ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
988
989
990
991
992
993
  		}
  
  out:
  		neigh_release(neigh);
  	}
  }
  
  static void ndisc_recv_rs(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
994
  	struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
  	unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
  	struct neighbour *neigh;
  	struct inet6_dev *idev;
b71d1d426   Eric Dumazet   inet: constify ip...
998
  	const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
  	struct ndisc_options ndopts;
  	u8 *lladdr = NULL;
  
  	if (skb->len < sizeof(*rs_msg))
  		return;
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1004
  	idev = __in6_dev_get(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
  	if (!idev) {
  		if (net_ratelimit())
  			ND_PRINTK1("ICMP6 RS: can't find in6 device
  ");
  		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 */
  	if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
  		if (net_ratelimit())
  			ND_PRINTK2("ICMP6 NS: invalid ND option, ignored
  ");
  		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) {
  		neigh_update(neigh, lladdr, NUD_STALE,
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
  		neigh_release(neigh);
  	}
  out:
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1047
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  }
31910575a   Pierre Ynard   [IPv6]: Export us...
1049
1050
1051
1052
1053
1054
  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...
1055
  	struct net *net = dev_net(ra->dev);
31910575a   Pierre Ynard   [IPv6]: Export us...
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  	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);
  	if (skb == NULL) {
  		err = -ENOBUFS;
  		goto errout;
  	}
  
  	nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
  	if (nlh == NULL) {
  		goto nla_put_failure;
  	}
  
  	ndmsg = nlmsg_data(nlh);
  	ndmsg->nduseropt_family = AF_INET6;
dbb2ed248   Pierre Ynard   [IPV6]: Add ifind...
1074
  	ndmsg->nduseropt_ifindex = ra->dev->ifindex;
31910575a   Pierre Ynard   [IPv6]: Export us...
1075
1076
1077
1078
1079
1080
1081
1082
1083
  	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);
  
  	NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
  		&ipv6_hdr(ra)->saddr);
  	nlmsg_end(skb, nlh);
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
1084
  	rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
31910575a   Pierre Ynard   [IPv6]: Export us...
1085
1086
1087
1088
1089
1090
  	return;
  
  nla_put_failure:
  	nlmsg_free(skb);
  	err = -EMSGSIZE;
  errout:
a18bc6959   Daniel Lezcano   [NETNS][IPV6] ndi...
1091
  	rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
31910575a   Pierre Ynard   [IPv6]: Export us...
1092
  }
65e9b62d4   Thomas Graf   ipv6: add special...
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  static inline int accept_ra(struct inet6_dev *in6_dev)
  {
  	/*
  	 * If forwarding is enabled, RA are not accepted unless the special
  	 * hybrid mode (accept_ra=2) is enabled.
  	 */
  	if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
  		return 0;
  
  	return in6_dev->cnf.accept_ra;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
  static void ndisc_router_discovery(struct sk_buff *skb)
  {
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1106
  	struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
  	struct neighbour *neigh = NULL;
  	struct inet6_dev *in6_dev;
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1109
  	struct rt6_info *rt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
  	int lifetime;
  	struct ndisc_options ndopts;
  	int optlen;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1113
  	unsigned int pref = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
  
  	__u8 * opt = (__u8 *)(ra_msg + 1);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1116
  	optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1118
  	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
1123
1124
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 RA: source address is not link-local.
  ");
  		return;
  	}
  	if (optlen < 0) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1125
  		ND_PRINTK2(KERN_WARNING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
1129
  			   "ICMPv6 RA: packet too short
  ");
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1130
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1131
1132
1133
1134
1135
1136
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 RA: from host or unauthorized router
  ");
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1137
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1138

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
  	/*
  	 *	set the RA_RECV flag in the interface
  	 */
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1142
  	in6_dev = __in6_dev_get(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
1145
1146
1147
1148
1149
  	if (in6_dev == NULL) {
  		ND_PRINTK0(KERN_ERR
  			   "ICMPv6 RA: can't find inet6 device for %s.
  ",
  			   skb->dev->name);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
  
  	if (!ndisc_parse_options(opt, optlen, &ndopts)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
1154
1155
1156
  		ND_PRINTK2(KERN_WARNING
  			   "ICMP6 RA: invalid ND options
  ");
  		return;
  	}
65e9b62d4   Thomas Graf   ipv6: add special...
1157
  	if (!accept_ra(in6_dev))
31ce8c71a   David Ward   ipv6: Update Neig...
1158
  		goto skip_linkparms;
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1159
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1160
1161
1162
  	/* skip link-specific parameters from interior routers */
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
  		goto skip_linkparms;
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1163
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1164

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  	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
  	 */
  	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);
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1183
1184
  	if (!in6_dev->cnf.accept_ra_defrtr)
  		goto skip_defrtr;
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1185
1186
  	if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
  		goto skip_defrtr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
  	lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1188
1189
1190
  #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...
1191
  	if (pref == ICMPV6_ROUTER_PREF_INVALID ||
6d5b78cdd   YOSHIFUJI Hideaki   [IPV6] NDISC: Fix...
1192
  	    !in6_dev->cnf.accept_ra_rtr_pref)
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1193
1194
  		pref = ICMPV6_ROUTER_PREF_MEDIUM;
  #endif
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1195
  	rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  
  	if (rt)
272174550   David Miller   net: Rename dst_g...
1198
  		neigh = dst_get_neighbour_noref(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
  
  	if (rt && lifetime == 0) {
  		neigh_clone(neigh);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1202
  		ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
1204
1205
1206
1207
1208
1209
  		rt = NULL;
  	}
  
  	if (rt == NULL && lifetime) {
  		ND_PRINTK3(KERN_DEBUG
  			   "ICMPv6 RA: adding default router.
  ");
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1210
  		rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
1213
1214
  		if (rt == NULL) {
  			ND_PRINTK0(KERN_ERR
  				   "ICMPv6 RA: %s() failed to add default route.
  ",
0dc47877a   Harvey Harrison   net: replace rema...
1215
  				   __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
  			return;
  		}
272174550   David Miller   net: Rename dst_g...
1218
  		neigh = dst_get_neighbour_noref(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
1221
1222
  		if (neigh == NULL) {
  			ND_PRINTK0(KERN_ERR
  				   "ICMPv6 RA: %s() got default router without neighbour.
  ",
0dc47877a   Harvey Harrison   net: replace rema...
1223
  				   __func__);
d8d1f30b9   Changli Gao   net-next: remove ...
1224
  			dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
  			return;
  		}
  		neigh->flags |= NTF_ROUTER;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1228
  	} else if (rt) {
22441cfa0   Pedro Ribeiro   IPV6: Fix default...
1229
  		rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
1232
  	}
  
  	if (rt)
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1233
  		rt->dst.expires = jiffies + (HZ * lifetime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
1236
1237
  
  	if (ra_msg->icmph.icmp6_hop_limit) {
  		in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
  		if (rt)
defb3519a   David S. Miller   net: Abstract awa...
1238
1239
  			dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
  				       ra_msg->icmph.icmp6_hop_limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
  	}
65f5c7c11   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1241
  skip_defrtr:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
  	/*
  	 *	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;
  			in6_dev->nd_parms->retrans_time = rtime;
  			in6_dev->tstamp = jiffies;
  			inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
  		}
  
  		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;
  
  			if (rtime != in6_dev->nd_parms->base_reachable_time) {
  				in6_dev->nd_parms->base_reachable_time = rtime;
  				in6_dev->nd_parms->gc_staletime = 3 * rtime;
  				in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
  				in6_dev->tstamp = jiffies;
  				inet6_ifinfo_notify(RTM_NEWLINK, in6_dev);
  			}
  		}
  	}
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1274
  skip_linkparms:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
1277
1278
1279
  	/*
  	 *	Process options.
  	 */
  
  	if (!neigh)
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1280
  		neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  				       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) {
  				ND_PRINTK2(KERN_WARNING
  					   "ICMPv6 RA: invalid link-layer address length
  ");
  				goto out;
  			}
  		}
  		neigh_update(neigh, lladdr, NUD_STALE,
  			     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE|
  			     NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
  			     NEIGH_UPDATE_F_ISROUTER);
  	}
65e9b62d4   Thomas Graf   ipv6: add special...
1300
  	if (!accept_ra(in6_dev))
31ce8c71a   David Ward   ipv6: Update Neig...
1301
  		goto out;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1302
  #ifdef CONFIG_IPV6_ROUTE_INFO
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1303
1304
  	if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
  		goto skip_routeinfo;
09c884d4c   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1305
  	if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1306
1307
1308
1309
  		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...
1310
1311
1312
1313
1314
1315
1316
  			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
  			if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
09c884d4c   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1317
  				continue;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1318
  			rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1319
  				      &ipv6_hdr(skb)->saddr);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1320
1321
  		}
  	}
9f56220fa   Andreas Hofmeister   ipv6: Do not use ...
1322
1323
  
  skip_routeinfo:
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1324
  #endif
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1325
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1326
1327
1328
  	/* skip link-specific ndopts from interior routers */
  	if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
  		goto out;
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1329
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1330

c4fd30eb1   YOSHIFUJI Hideaki   [IPV6]: ADDRCONF:...
1331
  	if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
1334
1335
  		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...
1336
1337
1338
  			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
1339
1340
1341
1342
  		}
  	}
  
  	if (ndopts.nd_opts_mtu) {
e69a4adc6   Al Viro   [IPV6]: Misc endi...
1343
  		__be32 n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
  		u32 mtu;
e69a4adc6   Al Viro   [IPV6]: Misc endi...
1345
1346
  		memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
  		mtu = ntohl(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
  
  		if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
  			ND_PRINTK2(KERN_WARNING
  				   "ICMPv6 RA: invalid mtu: %d
  ",
  				   mtu);
  		} else if (in6_dev->cnf.mtu6 != mtu) {
  			in6_dev->cnf.mtu6 = mtu;
  
  			if (rt)
defb3519a   David S. Miller   net: Abstract awa...
1357
  				dst_metric_set(&rt->dst, RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
  
  			rt6_mtu_change(skb->dev, mtu);
  		}
  	}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1362

31910575a   Pierre Ynard   [IPv6]: Export us...
1363
  	if (ndopts.nd_useropts) {
61cf46ad5   YOSHIFUJI Hideaki   [IPV6] NDISC: Spa...
1364
1365
1366
1367
1368
  		struct nd_opt_hdr *p;
  		for (p = ndopts.nd_useropts;
  		     p;
  		     p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
  			ndisc_ra_useropt(skb, p);
31910575a   Pierre Ynard   [IPv6]: Export us...
1369
1370
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
1376
  	if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 RA: invalid RA options");
  	}
  out:
  	if (rt)
d8d1f30b9   Changli Gao   net-next: remove ...
1377
  		dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
  	else if (neigh)
  		neigh_release(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
1383
1384
1385
  }
  
  static void ndisc_redirect_rcv(struct sk_buff *skb)
  {
  	struct inet6_dev *in6_dev;
  	struct icmp6hdr *icmph;
b71d1d426   Eric Dumazet   inet: constify ip...
1386
1387
  	const struct in6_addr *dest;
  	const struct in6_addr *target;	/* new first hop to destination */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
1389
1390
1391
1392
  	struct neighbour *neigh;
  	int on_link = 0;
  	struct ndisc_options ndopts;
  	int optlen;
  	u8 *lladdr = NULL;
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1393
  #ifdef CONFIG_IPV6_NDISC_NODETYPE
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1394
1395
1396
1397
1398
1399
1400
1401
  	switch (skb->ndisc_nodetype) {
  	case NDISC_NODETYPE_HOST:
  	case NDISC_NODETYPE_NODEFAULT:
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: from host or unauthorized router
  ");
  		return;
  	}
de357cc01   YOSHIFUJI Hideaki   [IPV6] NDISC: Don...
1402
  #endif
fadf6bf06   Templin, Fred L   [IPV6] SIT: Add P...
1403

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1404
  	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
1407
1408
1409
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: source address is not link-local.
  ");
  		return;
  	}
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1410
  	optlen = skb->tail - skb->transport_header;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
1412
1413
1414
1415
1416
1417
1418
  	optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
  
  	if (optlen < 0) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: packet too short
  ");
  		return;
  	}
cc70ab261   Arnaldo Carvalho de Melo   [ICMP6]: Introduc...
1419
  	icmph = icmp6_hdr(skb);
b71d1d426   Eric Dumazet   inet: constify ip...
1420
  	target = (const struct in6_addr *) (icmph + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
  	dest = target + 1;
  
  	if (ipv6_addr_is_multicast(dest)) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: destination address is multicast.
  ");
  		return;
  	}
  
  	if (ipv6_addr_equal(dest, target)) {
  		on_link = 1;
bf0b48dfc   Brian Haley   [IPv6]: Fix ICMPv...
1432
1433
  	} else if (ipv6_addr_type(target) !=
  		   (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1434
  		ND_PRINTK2(KERN_WARNING
bf0b48dfc   Brian Haley   [IPv6]: Fix ICMPv...
1435
1436
  			   "ICMPv6 Redirect: target address is not link-local unicast.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437
1438
  		return;
  	}
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1439
  	in6_dev = __in6_dev_get(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
  	if (!in6_dev)
  		return;
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1442
  	if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1445
  	/* RFC2461 8.1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
  	 *	The IP source address of the Redirect MUST be the same as the current
  	 *	first-hop router for the specified ICMP Destination Address.
  	 */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1449

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
1452
1453
  	if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: invalid ND options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
1455
1456
1457
1458
1459
1460
1461
1462
  		return;
  	}
  	if (ndopts.nd_opts_tgt_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
  					     skb->dev);
  		if (!lladdr) {
  			ND_PRINTK2(KERN_WARNING
  				   "ICMPv6 Redirect: invalid link-layer address length
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
1466
1467
1468
  			return;
  		}
  	}
  
  	neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
  	if (neigh) {
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1469
1470
  		rt6_redirect(dest, &ipv6_hdr(skb)->daddr,
  			     &ipv6_hdr(skb)->saddr, neigh, lladdr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
  			     on_link);
  		neigh_release(neigh);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
1475
1476
  }
  
  void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
1477
  			 const struct in6_addr *target)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
  {
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1479
  	struct net_device *dev = skb->dev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1480
  	struct net *net = dev_net(dev);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1481
  	struct sock *sk = net->ipv6.ndisc_sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1482
1483
1484
1485
1486
  	int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
  	struct sk_buff *buff;
  	struct icmp6hdr *icmph;
  	struct in6_addr saddr_buf;
  	struct in6_addr *addrp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
1488
1489
  	struct rt6_info *rt;
  	struct dst_entry *dst;
  	struct inet6_dev *idev;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1490
  	struct flowi6 fl6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1491
  	u8 *opt;
a7ae19922   Herbert Xu   ipv6: Remove all ...
1492
  	int hlen, tlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
  	int rd_len;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
  	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
95c385b4d   Neil Horman   [IPV6] ADDRCONF: ...
1496
  	if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
1498
1499
1500
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: no link-local address on %s
  ",
  			   dev->name);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1501
1502
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1504
  	if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
bf0b48dfc   Brian Haley   [IPv6]: Fix ICMPv...
1505
  	    ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
29556526b   Li Yewang   [IPV6]: fix BUG o...
1506
  		ND_PRINTK2(KERN_WARNING
bf0b48dfc   Brian Haley   [IPv6]: Fix ICMPv...
1507
1508
  			"ICMPv6 Redirect: target address is not link-local unicast.
  ");
29556526b   Li Yewang   [IPV6]: fix BUG o...
1509
1510
  		return;
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
1511
  	icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT,
95e41e93e   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1512
  			 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1513

4c9483b2f   David S. Miller   ipv6: Convert to ...
1514
  	dst = ip6_route_output(net, NULL, &fl6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
  	if (dst == NULL)
  		return;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1517
  	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
452edd598   David S. Miller   xfrm: Return dst ...
1518
  	if (IS_ERR(dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
1521
1522
1523
1524
1525
1526
  
  	rt = (struct rt6_info *) dst;
  
  	if (rt->rt6i_flags & RTF_GATEWAY) {
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 Redirect: destination is not a neighbour.
  ");
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1527
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
  	}
92d868292   David S. Miller   inetpeer: Move IC...
1529
1530
  	if (!rt->rt6i_peer)
  		rt6_bind_peer(rt, 1);
4d65a2465   Li Wei   ipv6: fix a bug i...
1531
  	if (!inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ))
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1532
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
  
  	if (dev->addr_len) {
  		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;
  			len += ndisc_opt_addr_space(dev);
  		} else
  			read_unlock_bh(&neigh->lock);
  	}
  
  	rd_len = min_t(unsigned int,
  		     IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
  	rd_len &= ~0x7;
  	len += rd_len;
a7ae19922   Herbert Xu   ipv6: Remove all ...
1549
1550
  	hlen = LL_RESERVED_SPACE(dev);
  	tlen = dev->needed_tailroom;
d54a81d34   David S. Miller   [IPV6] NDISC: Cal...
1551
1552
  	buff = sock_alloc_send_skb(sk,
  				   (MAX_HEADER + sizeof(struct ipv6hdr) +
a7ae19922   Herbert Xu   ipv6: Remove all ...
1553
  				    len + hlen + tlen),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
  				   1, &err);
  	if (buff == NULL) {
  		ND_PRINTK0(KERN_ERR
dae9de8e1   Brian Haley   IPv6: Print error...
1557
1558
1559
  			   "ICMPv6 Redirect: %s() failed to allocate an skb, err=%d.
  ",
  			   __func__, err);
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1560
  		goto release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
  	}
a7ae19922   Herbert Xu   ipv6: Remove all ...
1562
  	skb_reserve(buff, hlen);
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1563
  	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  		   IPPROTO_ICMPV6, len);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
1565
  	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
d10ba34b0   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1566
1567
  	skb_put(buff, len);
  	icmph = icmp6_hdr(buff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
1569
1570
1571
1572
1573
1574
1575
1576
  
  	memset(icmph, 0, sizeof(struct icmp6hdr));
  	icmph->icmp6_type = NDISC_REDIRECT;
  
  	/*
  	 *	copy target and destination addresses
  	 */
  
  	addrp = (struct in6_addr *)(icmph + 1);
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1577
  	*addrp = *target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1578
  	addrp++;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1579
  	*addrp = ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
  
  	opt = (u8*) (addrp + 1);
  
  	/*
  	 *	include target_address option
  	 */
  
  	if (ha)
  		opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
  					     dev->addr_len, dev->type);
  
  	/*
  	 *	build redirect option and copy skb over to the new packet.
  	 */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1594
  	memset(opt, 0, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
1596
1597
  	*(opt++) = ND_OPT_REDIRECT_HDR;
  	*(opt++) = (rd_len >> 3);
  	opt += 6;
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1598
  	memcpy(opt, ipv6_hdr(skb), rd_len - 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1600
  	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  					     len, IPPROTO_ICMPV6,
07f0757a6   Joe Perches   include/net net/ ...
1602
  					     csum_partial(icmph, len, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603

adf30907d   Eric Dumazet   net: skb->dst acc...
1604
  	skb_dst_set(buff, dst);
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1605
1606
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
edf391ff1   Neil Horman   snmp: add missing...
1607
  	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
b2e0b385d   Jan Engelhardt   netfilter: ipv6: ...
1608
  	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
6e23ae2a4   Patrick McHardy   [NETFILTER]: Intr...
1609
  		      dst_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
  	if (!err) {
5c5d244bd   Denis V. Lunev   ipv6: added net a...
1611
  		ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
a862f6a6d   Denis V. Lunev   ipv6: added net a...
1612
  		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
  	}
cfdf76474   Eric Dumazet   ipv6: some RCU co...
1614
  	rcu_read_unlock();
d73f08011   Ilpo Järvinen   ipv6/ndisc: join ...
1615
1616
1617
1618
  	return;
  
  release:
  	dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
1620
1621
1622
  }
  
  static void pndisc_redo(struct sk_buff *skb)
  {
140e26fcd   YOSHIFUJI Hideaki   [IPV6]: Fix NS ha...
1623
  	ndisc_recv_ns(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
1626
1627
1628
1629
1630
1631
1632
  	kfree_skb(skb);
  }
  
  int ndisc_rcv(struct sk_buff *skb)
  {
  	struct nd_msg *msg;
  
  	if (!pskb_may_pull(skb, skb->len))
  		return 0;
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1633
  	msg = (struct nd_msg *)skb_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634

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

0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1637
  	if (ipv6_hdr(skb)->hop_limit != 255) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1638
1639
1640
  		ND_PRINTK2(KERN_WARNING
  			   "ICMPv6 NDISC: invalid hop-limit: %d
  ",
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1641
  			   ipv6_hdr(skb)->hop_limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642
1643
1644
1645
  		return 0;
  	}
  
  	if (msg->icmph.icmp6_code != 0) {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1646
  		ND_PRINTK2(KERN_WARNING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
1648
1649
1650
1651
  			   "ICMPv6 NDISC: invalid ICMPv6 code: %d
  ",
  			   msg->icmph.icmp6_code);
  		return 0;
  	}
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
1652
  	memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
  	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...
1673
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
1675
1676
1677
1678
1679
1680
  
  	return 0;
  }
  
  static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
  	struct net_device *dev = ptr;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1681
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
1685
  
  	switch (event) {
  	case NETDEV_CHANGEADDR:
  		neigh_changeaddr(&nd_tbl, dev);
5b7c931df   Daniel Lezcano   [NETNS][IPV6] ip6...
1686
  		fib6_run_gc(~0UL, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1687
1688
1689
  		break;
  	case NETDEV_DOWN:
  		neigh_ifdown(&nd_tbl, dev);
5b7c931df   Daniel Lezcano   [NETNS][IPV6] ip6...
1690
  		fib6_run_gc(~0UL, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
  		break;
f47b94646   Ben Hutchings   ipv6: Send unsoli...
1692
1693
1694
  	case NETDEV_NOTIFY_PEERS:
  		ndisc_send_unsol_na(dev);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
  	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);
  		printk(KERN_WARNING
  			"process `%s' is using deprecated sysctl (%s) "
  			"net.ipv6.neigh.%s.%s; "
  			"Use net.ipv6.neigh.%s.%s_ms "
  			"instead.
  ",
  			warncomm, func,
  			dev_name, ctl->procname,
  			dev_name, ctl->procname);
  		warned++;
  	}
  }
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1726
  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
1727
1728
1729
1730
  {
  	struct net_device *dev = ctl->extra1;
  	struct inet6_dev *idev;
  	int ret;
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1731
1732
  	if ((strcmp(ctl->procname, "retrans_time") == 0) ||
  	    (strcmp(ctl->procname, "base_reachable_time") == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1733
  		ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default");
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1734
  	if (strcmp(ctl->procname, "retrans_time") == 0)
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1735
  		ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1736
1737
  
  	else if (strcmp(ctl->procname, "base_reachable_time") == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
  		ret = proc_dointvec_jiffies(ctl, write,
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1739
  					    buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1740
1741
  
  	else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) ||
ad02ac145   YOSHIFUJI Hideaki   [IPV6] NDISC: Fix...
1742
  		 (strcmp(ctl->procname, "base_reachable_time_ms") == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
  		ret = proc_dointvec_ms_jiffies(ctl, write,
8d65af789   Alexey Dobriyan   sysctl: remove "s...
1744
  					       buffer, lenp, ppos);
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1745
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1746
  		ret = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747
1748
  
  	if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) {
d12af679b   Eric W. Biederman   sysctl: fix neigh...
1749
  		if (ctl->data == &idev->nd_parms->base_reachable_time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
1751
1752
1753
1754
1755
1756
  			idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time);
  		idev->tstamp = jiffies;
  		inet6_ifinfo_notify(RTM_NEWLINK, idev);
  		in6_dev_put(idev);
  	}
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
1758
  
  #endif
2c8c1e729   Alexey Dobriyan   net: spread __net...
1759
  static int __net_init ndisc_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760
1761
1762
  {
  	struct ipv6_pinfo *np;
  	struct sock *sk;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1763
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764

1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1765
1766
  	err = inet_ctl_sock_create(&sk, PF_INET6,
  				   SOCK_RAW, IPPROTO_ICMPV6, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1767
1768
  	if (err < 0) {
  		ND_PRINTK0(KERN_ERR
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1769
1770
  			   "ICMPv6 NDISC: Failed to initialize the control socket (err %d).
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
  			   err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
1773
  		return err;
  	}
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1774
  	net->ipv6.ndisc_sk = sk;
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1775

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
  	np = inet6_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
  	np->hop_limit = 255;
  	/* Do not loopback ndisc messages */
  	np->mc_loop = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1780

1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1781
1782
  	return 0;
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
1783
  static void __net_exit ndisc_net_exit(struct net *net)
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1784
  {
1ed8516f0   Denis V. Lunev   [IPV6]: Simplify ...
1785
  	inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
  }
  
  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...
1800
1801
1802
  	/*
  	 * Initialize the neighbour table
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
  	neigh_table_init(&nd_tbl);
  
  #ifdef CONFIG_SYSCTL
54716e3be   Eric W. Biederman   net neigh: Decoup...
1806
  	err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6",
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
1807
  				    &ndisc_ifinfo_sysctl_change);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1808
1809
  	if (err)
  		goto out_unregister_pernet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  #endif
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1811
1812
1813
1814
1815
  	err = register_netdevice_notifier(&ndisc_netdev_notifier);
  	if (err)
  		goto out_unregister_sysctl;
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1816

1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1817
1818
1819
1820
1821
1822
1823
  out_unregister_sysctl:
  #ifdef CONFIG_SYSCTL
  	neigh_sysctl_unregister(&nd_tbl.parms);
  out_unregister_pernet:
  #endif
  	unregister_pernet_subsys(&ndisc_net_ops);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
1825
1826
1827
  }
  
  void ndisc_cleanup(void)
  {
36f73d0c3   Dmitry Mishin   [IPV6]: Add ndisc...
1828
  	unregister_netdevice_notifier(&ndisc_netdev_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
1830
1831
1832
  #ifdef CONFIG_SYSCTL
  	neigh_sysctl_unregister(&nd_tbl.parms);
  #endif
  	neigh_table_clear(&nd_tbl);
1762f7e88   Daniel Lezcano   [NETNS][IPV6] ndi...
1833
  	unregister_pernet_subsys(&ndisc_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
  }