xref: /netbsd-src/sys/netinet6/icmp6.c (revision 89c5a767f8fc7a4633b2d409966e2becbb98ff92)
1 /*	$NetBSD: icmp6.c,v 1.26 2000/03/01 12:49:44 itojun Exp $	*/
2 /*	$KAME: icmp6.c,v 1.71 2000/02/28 09:25:42 jinmei Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1982, 1986, 1988, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. All advertising materials mentioning features or use of this software
46  *    must display the following acknowledgement:
47  *	This product includes software developed by the University of
48  *	California, Berkeley and its contributors.
49  * 4. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
66  */
67 
68 #include "opt_inet.h"
69 #include "opt_ipsec.h"
70 
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/malloc.h>
74 #include <sys/mbuf.h>
75 #include <sys/protosw.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
78 #include <sys/time.h>
79 #include <sys/kernel.h>
80 #include <sys/syslog.h>
81 #include <sys/domain.h>
82 
83 #include <net/if.h>
84 #include <net/route.h>
85 #include <net/if_dl.h>
86 #include <net/if_types.h>
87 
88 #include <netinet/in.h>
89 #include <netinet/in_var.h>
90 #include <netinet/ip6.h>
91 #include <netinet6/ip6_var.h>
92 #include <netinet/icmp6.h>
93 #include <netinet6/mld6_var.h>
94 #include <netinet6/in6_pcb.h>
95 #include <netinet6/nd6.h>
96 #include <netinet6/in6_ifattach.h>
97 #include <netinet6/ip6protosw.h>
98 
99 
100 #ifdef IPSEC
101 #include <netinet6/ipsec.h>
102 #include <netkey/key.h>
103 #include <netkey/key_debug.h>
104 #endif
105 
106 #include "faith.h"
107 
108 #include <net/net_osdep.h>
109 
110 extern struct domain inet6domain;
111 
112 struct icmp6stat icmp6stat;
113 
114 extern struct in6pcb rawin6pcb;
115 extern struct timeval icmp6errratelim;
116 extern int icmp6_nodeinfo;
117 static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
118 extern int pmtu_expire;
119 
120 static int icmp6_rip6_input __P((struct mbuf **, int));
121 static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *,
122 				      struct mbuf *));
123 static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
124 static const char *icmp6_redirect_diag __P((struct in6_addr *,
125 	struct in6_addr *, struct in6_addr *));
126 static struct mbuf * ni6_input __P((struct mbuf *, int));
127 static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
128 			  struct ifnet **));
129 static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
130 				struct ifnet *, int));
131 static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
132 static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
133 
134 #ifdef COMPAT_RFC1885
135 static struct route_in6 icmp6_reflect_rt;
136 #endif
137 
138 void
139 icmp6_init()
140 {
141 	mld6_init();
142 	icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
143 }
144 
145 /*
146  * Generate an error packet of type error in response to bad IP6 packet.
147  */
148 void
149 icmp6_error(m, type, code, param)
150 	struct mbuf *m;
151 	int type, code, param;
152 {
153 	struct ip6_hdr *oip6, *nip6;
154 	struct icmp6_hdr *icmp6;
155 	u_int preplen;
156 	int off;
157 	u_char nxt;
158 
159 	icmp6stat.icp6s_error++;
160 
161 	if (m->m_flags & M_DECRYPTED) {
162 		icmp6stat.icp6s_canterror++;
163 		goto freeit;
164 	}
165 
166 #ifndef PULLDOWN_TEST
167 	IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
168 #else
169 	if (m->m_len < sizeof(struct ip6_hdr)) {
170 		m = m_pullup(m, sizeof(struct ip6_hdr));
171 		if (m == NULL)
172 			return;
173 	}
174 #endif
175 	oip6 = mtod(m, struct ip6_hdr *);
176 
177 	/*
178 	 * Multicast destination check. For unrecognized option errors,
179 	 * this check has already done in ip6_unknown_opt(), so we can
180 	 * check only for other errors.
181 	 */
182 	if ((m->m_flags & (M_BCAST|M_MCAST) ||
183 	     IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
184 	    (type != ICMP6_PACKET_TOO_BIG &&
185 	     (type != ICMP6_PARAM_PROB ||
186 	      code != ICMP6_PARAMPROB_OPTION)))
187 		goto freeit;
188 
189 	/* Source address check. XXX: the case of anycast source? */
190 	if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
191 	    IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
192 		goto freeit;
193 
194 	/*
195 	 * If the erroneous packet is also an ICMP error, discard it.
196 	 */
197 	off = sizeof(struct ip6_hdr);
198 	nxt = oip6->ip6_nxt;
199 	while (1) {		/* XXX: should avoid inf. loop explicitly? */
200 		struct ip6_ext *ip6e;
201 		struct icmp6_hdr *icp;
202 
203 		switch(nxt) {
204 		case IPPROTO_IPV6:
205 		case IPPROTO_IPV4:
206 		case IPPROTO_UDP:
207 		case IPPROTO_TCP:
208 		case IPPROTO_ESP:
209 		case IPPROTO_IPCOMP:
210 		case IPPROTO_FRAGMENT:
211 			/*
212 			 * ICMPv6 error must not be fragmented.
213 			 * XXX: but can we trust the sender?
214 			 */
215 		default:
216 			/* What if unknown header followed by ICMP error? */
217 			goto generate;
218 		case IPPROTO_ICMPV6:
219 #ifndef PULLDOWN_TEST
220 			IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
221 			icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
222 #else
223 			IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
224 				sizeof(*icp));
225 			if (icp == NULL) {
226 				icmp6stat.icp6s_tooshort++;
227 				return;
228 			}
229 #endif
230 			if (icp->icmp6_type < ICMP6_ECHO_REQUEST
231 			 || icp->icmp6_type == ND_REDIRECT) {
232 				/*
233 				 * ICMPv6 error
234 				 * Special case: for redirect (which is
235 				 * informational) we must not send icmp6 error.
236 				 */
237 				icmp6stat.icp6s_canterror++;
238 				goto freeit;
239 			} else {
240 				/* ICMPv6 informational */
241 				goto generate;
242 			}
243 		case IPPROTO_HOPOPTS:
244 		case IPPROTO_DSTOPTS:
245 		case IPPROTO_ROUTING:
246 		case IPPROTO_AH:
247 #ifndef PULLDOWN_TEST
248 			IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), );
249 			ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
250 #else
251 			IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off,
252 				sizeof(*ip6e));
253 			if (ip6e == NULL) {
254 				/*XXX stat */
255 				return;
256 			}
257 #endif
258 			if (nxt == IPPROTO_AH)
259 				off += (ip6e->ip6e_len + 2) << 2;
260 			else
261 				off += (ip6e->ip6e_len + 1) << 3;
262 			nxt = ip6e->ip6e_nxt;
263 			break;
264 		}
265 	}
266 
267   freeit:
268 	/*
269 	 * If we can't tell wheter or not we can generate ICMP6, free it.
270 	 */
271 	m_freem(m);
272 	return;
273 
274   generate:
275 	oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
276 
277 	/* Finally, do rate limitation check. */
278 	if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
279 		icmp6stat.icp6s_toofreq++;
280 		goto freeit;
281 	}
282 
283 	/*
284 	 * OK, ICMP6 can be generated.
285 	 */
286 
287 	if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
288 		m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
289 
290 	preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
291 	M_PREPEND(m, preplen, M_DONTWAIT);
292 	if (m && m->m_len < preplen)
293 		m = m_pullup(m, preplen);
294 	if (m == NULL) {
295 		printf("ENOBUFS in icmp6_error %d\n", __LINE__);
296 		return;
297 	}
298 
299 	nip6 = mtod(m, struct ip6_hdr *);
300 	nip6->ip6_src  = oip6->ip6_src;
301 	nip6->ip6_dst  = oip6->ip6_dst;
302 
303 	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
304 		oip6->ip6_src.s6_addr16[1] = 0;
305 	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
306 		oip6->ip6_dst.s6_addr16[1] = 0;
307 
308 	icmp6 = (struct icmp6_hdr *)(nip6 + 1);
309 	icmp6->icmp6_type = type;
310 	icmp6->icmp6_code = code;
311 	icmp6->icmp6_pptr = htonl((u_int32_t)param);
312 
313 	icmp6stat.icp6s_outhist[type]++;
314 	icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/
315 }
316 
317 /*
318  * Process a received ICMP6 message.
319  */
320 int
321 icmp6_input(mp, offp, proto)
322 	struct mbuf **mp;
323 	int *offp, proto;
324 {
325 	struct mbuf *m = *mp, *n;
326 	struct ip6_hdr *ip6, *nip6;
327 	struct icmp6_hdr *icmp6, *nicmp6;
328 	int off = *offp;
329 	int icmp6len = m->m_pkthdr.len - *offp;
330 	int code, sum, noff;
331 	struct sockaddr_in6 icmp6src;
332 
333 #ifndef PULLDOWN_TEST
334 	IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
335 	/* m might change if M_LOOP. So, call mtod after this */
336 #endif
337 
338 	/*
339 	 * Locate icmp6 structure in mbuf, and check
340 	 * that not corrupted and of at least minimum length
341 	 */
342 
343 	ip6 = mtod(m, struct ip6_hdr *);
344 	if (icmp6len < sizeof(struct icmp6_hdr)) {
345 		icmp6stat.icp6s_tooshort++;
346 		goto freeit;
347 	}
348 
349 	/*
350 	 * calculate the checksum
351 	 */
352 #ifndef PULLDOWN_TEST
353 	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
354 #else
355 	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
356 	if (icmp6 == NULL) {
357 		icmp6stat.icp6s_tooshort++;
358 		return IPPROTO_DONE;
359 	}
360 #endif
361 	code = icmp6->icmp6_code;
362 
363 	if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
364 		log(LOG_ERR,
365 		    "ICMP6 checksum error(%d|%x) %s\n",
366 		    icmp6->icmp6_type,
367 		    sum,
368 		    ip6_sprintf(&ip6->ip6_src));
369 		icmp6stat.icp6s_checksum++;
370 		goto freeit;
371 	}
372 
373 #if defined(NFAITH) && 0 < NFAITH
374 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
375 		/*
376 		 * Deliver very specific ICMP6 type only.
377 		 * This is important to deilver TOOBIG.  Otherwise PMTUD
378 		 * will not work.
379 		 */
380 		switch (icmp6->icmp6_type) {
381 		case ICMP6_DST_UNREACH:
382 		case ICMP6_PACKET_TOO_BIG:
383 		case ICMP6_TIME_EXCEEDED:
384 			break;
385 		default:
386 			goto freeit;
387 		}
388 	}
389 #endif
390 
391 #ifdef IPSEC
392 	/* drop it if it does not match the default policy */
393 	if (ipsec6_in_reject(m, NULL)) {
394 		ipsecstat.in_polvio++;
395 		goto freeit;
396 	}
397 #endif
398 
399 	icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
400 	icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
401 	if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
402 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
403 
404 	switch (icmp6->icmp6_type) {
405 
406 	case ICMP6_DST_UNREACH:
407 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
408 		switch (code) {
409 		case ICMP6_DST_UNREACH_NOROUTE:
410 			code = PRC_UNREACH_NET;
411 			break;
412 		case ICMP6_DST_UNREACH_ADMIN:
413 			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
414 			code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
415 			break;
416 		case ICMP6_DST_UNREACH_ADDR:
417 			code = PRC_HOSTDEAD;
418 			break;
419 #ifdef COMPAT_RFC1885
420 		case ICMP6_DST_UNREACH_NOTNEIGHBOR:
421 			code = PRC_UNREACH_SRCFAIL;
422 			break;
423 #else
424 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
425 			/* I mean "source address was incorrect." */
426 			code = PRC_PARAMPROB;
427 			break;
428 #endif
429 		case ICMP6_DST_UNREACH_NOPORT:
430 			code = PRC_UNREACH_PORT;
431 			break;
432 		default:
433 			goto badcode;
434 		}
435 		goto deliver;
436 		break;
437 
438 	case ICMP6_PACKET_TOO_BIG:
439 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
440 		if (code != 0)
441 			goto badcode;
442 
443 		code = PRC_MSGSIZE;
444 
445 		/*
446 		 * Updating the path MTU will be done after examining
447 		 * intermediate extension headers.
448 		 */
449 		goto deliver;
450 		break;
451 
452 	case ICMP6_TIME_EXCEEDED:
453 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
454 		switch (code) {
455 		case ICMP6_TIME_EXCEED_TRANSIT:
456 		case ICMP6_TIME_EXCEED_REASSEMBLY:
457 			code += PRC_TIMXCEED_INTRANS;
458 			break;
459 		default:
460 			goto badcode;
461 		}
462 		goto deliver;
463 		break;
464 
465 	case ICMP6_PARAM_PROB:
466 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
467 		switch (code) {
468 		case ICMP6_PARAMPROB_NEXTHEADER:
469 			code = PRC_UNREACH_PROTOCOL;
470 			break;
471 		case ICMP6_PARAMPROB_HEADER:
472 		case ICMP6_PARAMPROB_OPTION:
473 			code = PRC_PARAMPROB;
474 			break;
475 		default:
476 			goto badcode;
477 		}
478 		goto deliver;
479 		break;
480 
481 	case ICMP6_ECHO_REQUEST:
482 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
483 		if (code != 0)
484 			goto badcode;
485 		if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
486 			/* Give up remote */
487 			break;
488 		}
489 		if ((n->m_flags & M_EXT) != 0
490 		 || n->m_len < off + sizeof(struct icmp6_hdr)) {
491 			struct mbuf *n0 = n;
492 			const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
493 
494 			/*
495 			 * Prepare an internal mbuf. m_pullup() doesn't
496 			 * always copy the length we specified.
497 			 */
498 			if (maxlen >= MCLBYTES) {
499 #ifdef DIAGNOSTIC
500 				printf("MCLBYTES too small\n");
501 #endif
502 				/* Give up remote */
503 				m_freem(n0);
504 				break;
505 			}
506 			MGETHDR(n, M_DONTWAIT, n0->m_type);
507 			if (n && maxlen >= MHLEN) {
508 				MCLGET(n, M_DONTWAIT);
509 				if ((n->m_flags & M_EXT) == 0) {
510 					m_free(n);
511 					n = NULL;
512 				}
513 			}
514 			if (n == NULL) {
515 				/* Give up remote */
516 				m_freem(n0);
517 				break;
518 			}
519 			M_COPY_PKTHDR(n, n0);
520 			/*
521 			 * Copy IPv6 and ICMPv6 only.
522 			 */
523 			nip6 = mtod(n, struct ip6_hdr *);
524 			bcopy(ip6, nip6, sizeof(struct ip6_hdr));
525 			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
526 			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
527 			noff = sizeof(struct ip6_hdr);
528 			n->m_pkthdr.len = n->m_len =
529 				noff + sizeof(struct icmp6_hdr);
530 			/*
531 			 * Adjust mbuf. ip6_plen will be adjusted in
532 			 * ip6_output().
533 			 */
534 			m_adj(n0, off + sizeof(struct icmp6_hdr));
535 			n->m_pkthdr.len += n0->m_pkthdr.len;
536 			n->m_next = n0;
537 			n0->m_flags &= ~M_PKTHDR;
538 		} else {
539 			nip6 = mtod(n, struct ip6_hdr *);
540 			nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);
541 			noff = off;
542 		}
543 		nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
544 		nicmp6->icmp6_code = 0;
545 		if (n) {
546 			icmp6stat.icp6s_reflect++;
547 			icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
548 			icmp6_reflect(n, noff);
549 		}
550 		break;
551 
552 	case ICMP6_ECHO_REPLY:
553 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
554 		if (code != 0)
555 			goto badcode;
556 		break;
557 
558 	case MLD6_LISTENER_QUERY:
559 	case MLD6_LISTENER_REPORT:
560 		if (icmp6len < sizeof(struct mld6_hdr))
561 			goto badlen;
562 		if (icmp6->icmp6_type == MLD6_LISTENER_QUERY) /* XXX: ugly... */
563 			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
564 		else
565 			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
566 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
567 			/* give up local */
568 			mld6_input(m, off);
569 			m = NULL;
570 			goto freeit;
571 		}
572 		mld6_input(n, off);
573 		/* m stays. */
574 		break;
575 
576 	case MLD6_LISTENER_DONE:
577 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
578 		if (icmp6len < sizeof(struct mld6_hdr))	/* necessary? */
579 			goto badlen;
580 		break;		/* nothing to be done in kernel */
581 
582 	case MLD6_MTRACE_RESP:
583 	case MLD6_MTRACE:
584 		/* XXX: these two are experimental. not officially defind. */
585 		/* XXX: per-interface statistics? */
586 		break;		/* just pass it to applications */
587 
588 	case ICMP6_WRUREQUEST:	/* ICMP6_FQDN_QUERY */
589 	    {
590 		enum { WRU, FQDN } mode;
591 
592 		if (code != 0)
593 			goto badcode;
594 		if (!icmp6_nodeinfo)
595 			break;
596 
597 		if (icmp6len == sizeof(struct icmp6_hdr) + 4)
598 			mode = WRU;
599 		else if (icmp6len >= sizeof(struct icmp6_hdr) + 8) /* XXX */
600 			mode = FQDN;
601 		else
602 			goto badlen;
603 
604 		if (mode == FQDN) {
605 #ifndef PULLDOWN_TEST
606 			IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
607 					 IPPROTO_DONE);
608 #endif
609 			n = m_copy(m, 0, M_COPYALL);
610 			if (n)
611 				n = ni6_input(n, off);
612 			if (n)
613 				noff = sizeof(struct ip6_hdr);
614 		} else {
615 			u_char *p;
616 			int maxlen, maxhlen;
617 
618 			maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
619 			if (maxlen >= MCLBYTES) {
620 #ifdef DIAGNOSTIC
621 				printf("MCLBYTES too small\n");
622 #endif
623 				/* Give up remote */
624 				break;
625 			}
626 			MGETHDR(n, M_DONTWAIT, m->m_type);
627 			if (n && maxlen > MHLEN) {
628 				MCLGET(n, M_DONTWAIT);
629 				if ((n->m_flags & M_EXT) == 0) {
630 					m_free(n);
631 					n = NULL;
632 				}
633 			}
634 			if (n == NULL) {
635 				/* Give up remote */
636 				break;
637 			}
638 			n->m_len = 0;
639 			maxhlen = M_TRAILINGSPACE(n) - maxlen;
640 			if (maxhlen > hostnamelen)
641 				maxhlen = hostnamelen;
642 			/*
643 			 * Copy IPv6 and ICMPv6 only.
644 			 */
645 			nip6 = mtod(n, struct ip6_hdr *);
646 			bcopy(ip6, nip6, sizeof(struct ip6_hdr));
647 			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
648 			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
649 			p = (u_char *)(nicmp6 + 1);
650 			bzero(p, 4);
651 			bcopy(hostname, p + 4, maxhlen);
652 			noff = sizeof(struct ip6_hdr);
653 			M_COPY_PKTHDR(n, m); /* just for recvif */
654 			n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
655 				sizeof(struct icmp6_hdr) + 4 + maxhlen;
656 			nicmp6->icmp6_type = ICMP6_WRUREPLY;
657 			nicmp6->icmp6_code = 0;
658 		}
659 #undef hostnamelen
660 		if (n) {
661 			icmp6stat.icp6s_reflect++;
662 			icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
663 			icmp6_reflect(n, noff);
664 		}
665 		break;
666 	    }
667 
668 	case ICMP6_WRUREPLY:
669 		if (code != 0)
670 			goto badcode;
671 		break;
672 
673 	case ND_ROUTER_SOLICIT:
674 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
675 		if (code != 0)
676 			goto badcode;
677 		if (icmp6len < sizeof(struct nd_router_solicit))
678 			goto badlen;
679 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
680 			/* give up local */
681 			nd6_rs_input(m, off, icmp6len);
682 			m = NULL;
683 			goto freeit;
684 		}
685 		nd6_rs_input(n, off, icmp6len);
686 		/* m stays. */
687 		break;
688 
689 	case ND_ROUTER_ADVERT:
690 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
691 		if (code != 0)
692 			goto badcode;
693 		if (icmp6len < sizeof(struct nd_router_advert))
694 			goto badlen;
695 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
696 			/* give up local */
697 			nd6_ra_input(m, off, icmp6len);
698 			m = NULL;
699 			goto freeit;
700 		}
701 		nd6_ra_input(n, off, icmp6len);
702 		/* m stays. */
703 		break;
704 
705 	case ND_NEIGHBOR_SOLICIT:
706 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
707 		if (code != 0)
708 			goto badcode;
709 		if (icmp6len < sizeof(struct nd_neighbor_solicit))
710 			goto badlen;
711 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
712 			/* give up local */
713 			nd6_ns_input(m, off, icmp6len);
714 			m = NULL;
715 			goto freeit;
716 		}
717 		nd6_ns_input(n, off, icmp6len);
718 		/* m stays. */
719 		break;
720 
721 	case ND_NEIGHBOR_ADVERT:
722 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
723 		if (code != 0)
724 			goto badcode;
725 		if (icmp6len < sizeof(struct nd_neighbor_advert))
726 			goto badlen;
727 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
728 			/* give up local */
729 			nd6_na_input(m, off, icmp6len);
730 			m = NULL;
731 			goto freeit;
732 		}
733 		nd6_na_input(n, off, icmp6len);
734 		/* m stays. */
735 		break;
736 
737 	case ND_REDIRECT:
738 		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
739 		if (code != 0)
740 			goto badcode;
741 		if (icmp6len < sizeof(struct nd_redirect))
742 			goto badlen;
743 		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
744 			/* give up local */
745 			icmp6_redirect_input(m, off);
746 			m = NULL;
747 			goto freeit;
748 		}
749 		icmp6_redirect_input(n, off);
750 		/* m stays. */
751 		break;
752 
753 	case ICMP6_ROUTER_RENUMBERING:
754 		if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
755 		    code != ICMP6_ROUTER_RENUMBERING_RESULT)
756 			goto badcode;
757 		if (icmp6len < sizeof(struct icmp6_router_renum))
758 			goto badlen;
759 		break;
760 
761 	default:
762 		printf("icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
763 		       icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
764 		       ip6_sprintf(&ip6->ip6_dst),
765 		       m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0);
766 		if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
767 			/* ICMPv6 error: MUST deliver it by spec... */
768 			code = PRC_NCMDS;
769 			/* deliver */
770 		} else {
771 			/* ICMPv6 informational: MUST not deliver */
772 			break;
773 		}
774 	deliver:
775 		if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
776 			icmp6stat.icp6s_tooshort++;
777 			goto freeit;
778 		}
779 #ifndef PULLDOWN_TEST
780 		IP6_EXTHDR_CHECK(m, off,
781 			sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
782 			IPPROTO_DONE);
783 		icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
784 #else
785 		IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
786 			sizeof(*icmp6) + sizeof(struct ip6_hdr));
787 		if (icmp6 == NULL) {
788 			icmp6stat.icp6s_tooshort++;
789 			return IPPROTO_DONE;
790 		}
791 #endif
792 		bzero(&icmp6src, sizeof(icmp6src));
793 		icmp6src.sin6_len = sizeof(struct sockaddr_in6);
794 		icmp6src.sin6_family = AF_INET6;
795 		icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
796 
797 		/* Detect the upper level protocol */
798 	    {
799 		void (*ctlfunc) __P((int, struct sockaddr *, void *));
800 		struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1);
801 		u_int8_t nxt = eip6->ip6_nxt;
802 		int eoff = off + sizeof(struct icmp6_hdr) +
803 			sizeof(struct ip6_hdr);
804 		struct ip6ctlparam ip6cp;
805 		struct in6_addr *finaldst = NULL;
806 		int icmp6type = icmp6->icmp6_type;
807 		struct ip6_frag *fh;
808 		struct ip6_rthdr *rth;
809 		struct ip6_rthdr0 *rth0;
810 		int rthlen;
811 
812 		while (1) { /* XXX: should avoid inf. loop explicitly? */
813 			struct ip6_ext *eh;
814 
815 			switch(nxt) {
816 			case IPPROTO_HOPOPTS:
817 			case IPPROTO_DSTOPTS:
818 			case IPPROTO_AH:
819 #ifndef PULLDOWN_TEST
820 				IP6_EXTHDR_CHECK(m, 0, eoff +
821 						 sizeof(struct ip6_ext),
822 						 IPPROTO_DONE);
823 				eh = (struct ip6_ext *)(mtod(m, caddr_t)
824 							+ eoff);
825 #else
826 				IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
827 					eoff, sizeof(*eh));
828 				if (eh == NULL) {
829 					icmp6stat.icp6s_tooshort++;
830 					return IPPROTO_DONE;
831 				}
832 #endif
833 
834 				if (nxt == IPPROTO_AH)
835 					eoff += (eh->ip6e_len + 2) << 2;
836 				else
837 					eoff += (eh->ip6e_len + 1) << 3;
838 				nxt = eh->ip6e_nxt;
839 				break;
840 			case IPPROTO_ROUTING:
841 				/*
842 				 * When the erroneous packet contains a
843 				 * routing header, we should examine the
844 				 * header to determine the final destination.
845 				 * Otherwise, we can't properly update
846 				 * information that depends on the final
847 				 * destination (e.g. path MTU).
848 				 */
849 #ifndef PULLDOWN_TEST
850 				IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
851 						 IPPROTO_DONE);
852 				rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
853 							   + eoff);
854 #else
855 				IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
856 					eoff, sizeof(*rth));
857 				if (rth == NULL) {
858 					icmp6stat.icp6s_tooshort++;
859 					return IPPROTO_DONE;
860 				}
861 #endif
862 				rthlen = (rth->ip6r_len + 1) << 3;
863 				/*
864 				 * XXX: currently there is no
865 				 * officially defined type other
866 				 * than type-0.
867 				 * Note that if the segment left field
868 				 * is 0, all intermediate hops must
869 				 * have been passed.
870 				 */
871 				if (rth->ip6r_segleft &&
872 				    rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
873 					int hops;
874 
875 #ifndef PULLDOWN_TEST
876 					IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
877 							 IPPROTO_DONE);
878 					rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
879 #else
880 					IP6_EXTHDR_GET(rth0,
881 						       struct ip6_rthdr0 *, m,
882 						       eoff, rthlen);
883 					if (rth0 == NULL) {
884 						icmp6stat.icp6s_tooshort++;
885 						return IPPROTO_DONE;
886 					}
887 #endif
888 					/* just ignore a bogus header */
889 					if ((rth0->ip6r0_len % 2) == 0 &&
890 					    (hops = rth0->ip6r0_len/2))
891 						finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
892 				}
893 				eoff += rthlen;
894 				nxt = rth->ip6r_nxt;
895 				break;
896 			case IPPROTO_FRAGMENT:
897 #ifndef PULLDOWN_TEST
898 				IP6_EXTHDR_CHECK(m, 0, eoff +
899 						 sizeof(struct ip6_frag),
900 						 IPPROTO_DONE);
901 				fh = (struct ip6_frag *)(mtod(m, caddr_t)
902 							 + eoff);
903 #else
904 				IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
905 					eoff, sizeof(*fh));
906 				if (fh == NULL) {
907 					icmp6stat.icp6s_tooshort++;
908 					return IPPROTO_DONE;
909 				}
910 #endif
911 				/*
912 				 * Data after a fragment header is meaningless
913 				 * unless it is the first fragment, but
914 				 * we'll go to the notify label for path MTU
915 				 * discovery.
916 				 */
917 				if (fh->ip6f_offlg & IP6F_OFF_MASK)
918 					goto notify;
919 
920 				eoff += sizeof(struct ip6_frag);
921 				nxt = fh->ip6f_nxt;
922 				break;
923 			default:
924 				/*
925 				 * This case includes ESP and the No Next
926 				 * Header. In such cases going to the notify
927 				 * label does not have any meaning
928 				 * (i.e. ctlfunc will be NULL), but we go
929 				 * anyway since we might have to update
930 				 * path MTU information.
931 				 */
932 				goto notify;
933 			}
934 		}
935 	    notify:
936 #ifndef PULLDOWN_TEST
937 		icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
938 #else
939 		IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
940 			sizeof(*icmp6) + sizeof(struct ip6_hdr));
941 		if (icmp6 == NULL) {
942 			icmp6stat.icp6s_tooshort++;
943 			return IPPROTO_DONE;
944 		}
945 #endif
946 		if (icmp6type == ICMP6_PACKET_TOO_BIG) {
947 			if (finaldst == NULL)
948 				finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
949 			icmp6_mtudisc_update(finaldst, icmp6, m);
950 		}
951 
952 		ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
953 			(inet6sw[ip6_protox[nxt]].pr_ctlinput);
954 		if (ctlfunc) {
955 			ip6cp.ip6c_m = m;
956 			ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
957 			ip6cp.ip6c_off = eoff;
958 			(*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp);
959 		}
960 	    }
961 		break;
962 
963 	badcode:
964 		icmp6stat.icp6s_badcode++;
965 		break;
966 
967 	badlen:
968 		icmp6stat.icp6s_badlen++;
969 		break;
970 	}
971 
972 	icmp6_rip6_input(&m, *offp);
973 	return IPPROTO_DONE;
974 
975  freeit:
976 	m_freem(m);
977 	return IPPROTO_DONE;
978 }
979 
980 static void
981 icmp6_mtudisc_update(dst, icmp6, m)
982 	struct in6_addr *dst;
983 	struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */
984 	struct mbuf *m;	/* currently unused but added for scoped addrs */
985 {
986 	u_int mtu = ntohl(icmp6->icmp6_mtu);
987 	struct rtentry *rt = NULL;
988 	struct sockaddr_in6 sin6;
989 
990 	bzero(&sin6, sizeof(sin6));
991 	sin6.sin6_family = PF_INET6;
992 	sin6.sin6_len = sizeof(struct sockaddr_in6);
993 	sin6.sin6_addr = *dst;
994 	/* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
995 	rt = rtalloc1((struct sockaddr *)&sin6, 1);	/*clone*/
996 	if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
997 		if (rt)
998 			RTFREE(rt);
999 		rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
1000 	}
1001 
1002 	if (rt && (rt->rt_flags & RTF_HOST)
1003 	    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
1004 		if (mtu < IPV6_MMTU) {
1005 				/* xxx */
1006 			rt->rt_rmx.rmx_locks |= RTV_MTU;
1007 		} else if (mtu < rt->rt_ifp->if_mtu &&
1008 			   rt->rt_rmx.rmx_mtu > mtu) {
1009 			rt->rt_rmx.rmx_mtu = mtu;
1010 		}
1011 	}
1012 	if (rt)
1013 		RTFREE(rt);
1014 }
1015 
1016 /*
1017  * Process a Node Information Query
1018  */
1019 #ifndef offsetof		/* XXX */
1020 #define	offsetof(type, member)	((size_t)(&((type *)0)->member))
1021 #endif
1022 
1023 static struct mbuf *
1024 ni6_input(m, off)
1025 	struct mbuf *m;
1026 	int off;
1027 {
1028 	struct icmp6_nodeinfo *ni6, *nni6;
1029 	struct mbuf *n = NULL;
1030 	u_int16_t qtype;
1031 	int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1032 	struct ni_reply_fqdn *fqdn;
1033 	int addrs;		/* for NI_QTYPE_NODEADDR */
1034 	struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
1035 
1036 #ifndef PULLDOWN_TEST
1037 	ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
1038 #else
1039 	IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
1040 	if (ni6 == NULL) {
1041 		/* m is already reclaimed */
1042 		return NULL;
1043 	}
1044 #endif
1045 	qtype = ntohs(ni6->ni_qtype);
1046 
1047 	switch(qtype) {
1048 	 case NI_QTYPE_NOOP:
1049 		 break;		/* no reply data */
1050 	 case NI_QTYPE_SUPTYPES:
1051 		 goto bad;	/* xxx: to be implemented */
1052 		 break;
1053 	 case NI_QTYPE_FQDN:
1054 		 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
1055 			 hostnamelen;
1056 		 break;
1057 	 case NI_QTYPE_NODEADDR:
1058 		 addrs = ni6_addrs(ni6, m, &ifp);
1059 		 if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES)
1060 			 replylen = MCLBYTES; /* XXX: we'll truncate later */
1061 
1062 		 break;
1063 	 default:
1064 		 /*
1065 		  * XXX: We must return a reply with the ICMP6 code
1066 		  * `unknown Qtype' in this case. However we regard the case
1067 		  * as an FQDN query for backward compatibility.
1068 		  * Older versions set a random value to this field,
1069 		  * so it rarely varies in the defined qtypes.
1070 		  * But the mechanism is not reliable...
1071 		  * maybe we should obsolete older versions.
1072 		  */
1073 		 qtype = NI_QTYPE_FQDN;
1074 		 replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
1075 			 hostnamelen;
1076 		 break;
1077 	}
1078 
1079 	/* allocate a mbuf to reply. */
1080 	MGETHDR(n, M_DONTWAIT, m->m_type);
1081 	if (n == NULL) {
1082 		m_freem(m);
1083 		return(NULL);
1084 	}
1085 	M_COPY_PKTHDR(n, m); /* just for recvif */
1086 	if (replylen > MHLEN) {
1087 		if (replylen > MCLBYTES)
1088 			 /*
1089 			  * XXX: should we try to allocate more? But MCLBYTES is
1090 			  * probably much larger than IPV6_MMTU...
1091 			  */
1092 			goto bad;
1093 		MCLGET(n, M_DONTWAIT);
1094 		if ((n->m_flags & M_EXT) == 0) {
1095 			goto bad;
1096 		}
1097 	}
1098 	n->m_pkthdr.len = n->m_len = replylen;
1099 
1100 	/* copy mbuf header and IPv6 + Node Information base headers */
1101 	bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
1102 	nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
1103 	bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
1104 
1105 	/* qtype dependent procedure */
1106 	switch (qtype) {
1107 	 case NI_QTYPE_NOOP:
1108 		 nni6->ni_flags = 0;
1109 		 break;
1110 	 case NI_QTYPE_SUPTYPES:
1111 		 goto bad;	/* xxx: to be implemented */
1112 		 break;
1113 	 case NI_QTYPE_FQDN:
1114 		 if (hostnamelen > 255) { /* XXX: rare case, but may happen */
1115 			 printf("ni6_input: "
1116 				"hostname length(%d) is too large for reply\n",
1117 				hostnamelen);
1118 			 goto bad;
1119 		 }
1120 		 fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
1121 						 sizeof(struct ip6_hdr) +
1122 						 sizeof(struct icmp6_nodeinfo));
1123 		 nni6->ni_flags = 0; /* XXX: meaningless TTL */
1124 		 fqdn->ni_fqdn_ttl = 0;	/* ditto. */
1125 		 fqdn->ni_fqdn_namelen = hostnamelen;
1126 		 bcopy(hostname, &fqdn->ni_fqdn_name[0], hostnamelen);
1127 		 break;
1128 	 case NI_QTYPE_NODEADDR:
1129 	 {
1130 		 int lenlim, copied;
1131 
1132 		 if (n->m_flags & M_EXT)
1133 			 lenlim = MCLBYTES - sizeof(struct ip6_hdr) -
1134 				 sizeof(struct icmp6_nodeinfo);
1135 		 else
1136 			 lenlim = MHLEN - sizeof(struct ip6_hdr) -
1137 				 sizeof(struct icmp6_nodeinfo);
1138 		 copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
1139 		 /* XXX: reset mbuf length */
1140 		 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
1141 			 sizeof(struct icmp6_nodeinfo) + copied;
1142 		 break;
1143 	 }
1144 	 default:
1145 		 break;		/* XXX impossible! */
1146 	}
1147 
1148 	nni6->ni_type = ICMP6_NI_REPLY;
1149 	nni6->ni_code = ICMP6_NI_SUCESS;
1150 	m_freem(m);
1151 	return(n);
1152 
1153   bad:
1154 	m_freem(m);
1155 	if (n)
1156 		m_freem(n);
1157 	return(NULL);
1158 }
1159 #undef hostnamelen
1160 
1161 /*
1162  * calculate the number of addresses to be returned in the node info reply.
1163  */
1164 static int
1165 ni6_addrs(ni6, m, ifpp)
1166 	struct icmp6_nodeinfo *ni6;
1167 	struct mbuf *m;
1168 	struct ifnet **ifpp;
1169 {
1170 	register struct ifnet *ifp;
1171 	register struct in6_ifaddr *ifa6;
1172 	register struct ifaddr *ifa;
1173 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1174 	int addrs = 0, addrsofif, iffound = 0;
1175 
1176 	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
1177 	{
1178 		addrsofif = 0;
1179 		for (ifa = ifp->if_addrlist.tqh_first; ifa;
1180 		     ifa = ifa->ifa_list.tqe_next)
1181 		{
1182 			if (ifa->ifa_addr->sa_family != AF_INET6)
1183 				continue;
1184 			ifa6 = (struct in6_ifaddr *)ifa;
1185 
1186 			if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) &&
1187 			    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1188 					       &ifa6->ia_addr.sin6_addr))
1189 				iffound = 1;
1190 
1191 			/*
1192 			 * IPv4-mapped addresses can only be returned by a
1193 			 * Node Information proxy, since they represent
1194 			 * addresses of IPv4-only nodes, which perforce do
1195 			 * not implement this protocol.
1196 			 * [icmp-name-lookups-05]
1197 			 * So we don't support NI_NODEADDR_FLAG_COMPAT in
1198 			 * this function at this moment.
1199 			 */
1200 
1201 			if (ifa6->ia6_flags & IN6_IFF_ANYCAST)
1202 				continue; /* we need only unicast addresses */
1203 
1204 			if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL |
1205 					      NI_NODEADDR_FLAG_SITELOCAL |
1206 					      NI_NODEADDR_FLAG_GLOBAL)) == 0)
1207 				continue;
1208 
1209 			/* What do we have to do about ::1? */
1210 			switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1211 			 case IPV6_ADDR_SCOPE_LINKLOCAL:
1212 				if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
1213 					addrsofif++;
1214 				break;
1215 			 case IPV6_ADDR_SCOPE_SITELOCAL:
1216 				if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
1217 					addrsofif++;
1218 				break;
1219 			 case IPV6_ADDR_SCOPE_GLOBAL:
1220 				 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
1221 					 addrsofif++;
1222 				 break;
1223 			 default:
1224 				 continue;
1225 			}
1226 		}
1227 		if (iffound) {
1228 			*ifpp = ifp;
1229 			return(addrsofif);
1230 		}
1231 
1232 		addrs += addrsofif;
1233 	}
1234 
1235 	return(addrs);
1236 }
1237 
1238 static int
1239 ni6_store_addrs(ni6, nni6, ifp0, resid)
1240 	struct icmp6_nodeinfo *ni6, *nni6;
1241 	struct ifnet *ifp0;
1242 	int resid;
1243 {
1244 	register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
1245 	register struct in6_ifaddr *ifa6;
1246 	register struct ifaddr *ifa;
1247 	int docopy, copied = 0;
1248 	u_char *cp = (u_char *)(nni6 + 1);
1249 
1250 	if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL))
1251 		return(0);	/* needless to copy */
1252 
1253 	for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
1254 	{
1255 		for (ifa = ifp->if_addrlist.tqh_first; ifa;
1256 		     ifa = ifa->ifa_list.tqe_next)
1257 		{
1258 			docopy = 0;
1259 
1260 			if (ifa->ifa_addr->sa_family != AF_INET6)
1261 				continue;
1262 			ifa6 = (struct in6_ifaddr *)ifa;
1263 
1264 			if (ifa6->ia6_flags & IN6_IFF_ANYCAST) {
1265 				/* just experimental. not in the spec. */
1266 				if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
1267 					docopy = 1;
1268 				else
1269 					continue;
1270 			}
1271 			else {	/* unicast address */
1272 				if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST)
1273 					continue;
1274 				else
1275 					docopy = 1;
1276 			}
1277 
1278 			/* What do we have to do about ::1? */
1279 			switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1280 			 case IPV6_ADDR_SCOPE_LINKLOCAL:
1281 				if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL)
1282 					docopy = 1;
1283 				break;
1284 			 case IPV6_ADDR_SCOPE_SITELOCAL:
1285 				if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL)
1286 					docopy = 1;
1287 				break;
1288 			 case IPV6_ADDR_SCOPE_GLOBAL:
1289 				 if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL)
1290 					 docopy = 1;
1291 				 break;
1292 			 default:
1293 				 continue;
1294 			}
1295 
1296 			if (docopy) {
1297 				if (resid < sizeof(struct in6_addr)) {
1298 					/*
1299 					 * We give up much more copy.
1300 					 * Set the truncate flag and return.
1301 					 */
1302 					nni6->ni_flags |=
1303 						NI_NODEADDR_FLAG_TRUNCATE;
1304 					return(copied);
1305 				}
1306 				bcopy(&ifa6->ia_addr.sin6_addr, cp,
1307 				      sizeof(struct in6_addr));
1308 				/* XXX: KAME link-local hack; remove ifindex */
1309 				if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
1310 					((struct in6_addr *)cp)->s6_addr16[1] = 0;
1311 				cp += sizeof(struct in6_addr);
1312 				resid -= sizeof(struct in6_addr);
1313 				copied += sizeof(struct in6_addr);
1314 			}
1315 		}
1316 		if (ifp0)	/* we need search only on the specified IF */
1317 			break;
1318 	}
1319 
1320 	return(copied);
1321 }
1322 
1323 /*
1324  * XXX almost dup'ed code with rip6_input.
1325  */
1326 static int
1327 icmp6_rip6_input(mp, off)
1328 	struct	mbuf **mp;
1329 	int	off;
1330 {
1331 	struct mbuf *m = *mp;
1332 	register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1333 	register struct in6pcb *in6p;
1334 	struct in6pcb *last = NULL;
1335 	struct sockaddr_in6 rip6src;
1336 	struct icmp6_hdr *icmp6;
1337 	struct mbuf *opts = NULL;
1338 
1339 #ifndef PULLDOWN_TEST
1340 	/* this is assumed to be safe. */
1341 	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
1342 #else
1343 	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
1344 	if (icmp6 == NULL) {
1345 		/* m is already reclaimed */
1346 		return IPPROTO_DONE;
1347 	}
1348 #endif
1349 
1350 	bzero(&rip6src, sizeof(rip6src));
1351 	rip6src.sin6_len = sizeof(struct sockaddr_in6);
1352 	rip6src.sin6_family = AF_INET6;
1353 	rip6src.sin6_addr = ip6->ip6_src;
1354 	if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1355 		rip6src.sin6_addr.s6_addr16[1] = 0;
1356 	if (m->m_pkthdr.rcvif) {
1357 		if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
1358 			rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
1359 		else
1360 			rip6src.sin6_scope_id = 0;
1361 	} else
1362 		rip6src.sin6_scope_id = 0;
1363 
1364 	for (in6p = rawin6pcb.in6p_next;
1365 	     in6p != &rawin6pcb; in6p = in6p->in6p_next)
1366 	{
1367 		if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
1368 			continue;
1369 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1370 		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1371 			continue;
1372 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1373 		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1374 			continue;
1375 		if (in6p->in6p_icmp6filt
1376 		    && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
1377 				 in6p->in6p_icmp6filt))
1378 			continue;
1379 		if (last) {
1380 			struct	mbuf *n;
1381 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
1382 				if (last->in6p_flags & IN6P_CONTROLOPTS)
1383 					ip6_savecontrol(last, &opts, ip6, n);
1384 				/* strip intermediate headers */
1385 				m_adj(n, off);
1386 				if (sbappendaddr(&last->in6p_socket->so_rcv,
1387 						 (struct sockaddr *)&rip6src,
1388 						 n, opts) == 0) {
1389 					/* should notify about lost packet */
1390 					m_freem(n);
1391 					if (opts)
1392 						m_freem(opts);
1393 				} else
1394 					sorwakeup(last->in6p_socket);
1395 				opts = NULL;
1396 			}
1397 		}
1398 		last = in6p;
1399 	}
1400 	if (last) {
1401 		if (last->in6p_flags & IN6P_CONTROLOPTS)
1402 			ip6_savecontrol(last, &opts, ip6, m);
1403 		/* strip intermediate headers */
1404 		m_adj(m, off);
1405 		if (sbappendaddr(&last->in6p_socket->so_rcv,
1406 				(struct sockaddr *)&rip6src, m, opts) == 0) {
1407 			m_freem(m);
1408 			if (opts)
1409 				m_freem(opts);
1410 		} else
1411 			sorwakeup(last->in6p_socket);
1412 	} else {
1413 		m_freem(m);
1414 		ip6stat.ip6s_delivered--;
1415 	}
1416 	return IPPROTO_DONE;
1417 }
1418 
1419 /*
1420  * Reflect the ip6 packet back to the source.
1421  * OFF points to the icmp6 header, counted from the top of the mbuf.
1422  */
1423 void
1424 icmp6_reflect(m, off)
1425 	struct	mbuf *m;
1426 	size_t off;
1427 {
1428 	struct ip6_hdr *ip6;
1429 	struct icmp6_hdr *icmp6;
1430 	struct in6_ifaddr *ia;
1431 	struct in6_addr t, *src = 0;
1432 	int plen;
1433 	int type, code;
1434 	struct ifnet *outif = NULL;
1435 #ifdef COMPAT_RFC1885
1436 	int mtu = IPV6_MMTU;
1437 	struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
1438 #endif
1439 
1440 	/* too short to reflect */
1441 	if (off < sizeof(struct ip6_hdr)) {
1442 		printf("sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
1443 		       (u_long)off, (u_long)sizeof(struct ip6_hdr),
1444 		       __FILE__, __LINE__);
1445 		goto bad;
1446 	}
1447 
1448 	/*
1449 	 * If there are extra headers between IPv6 and ICMPv6, strip
1450 	 * off that header first.
1451 	 */
1452 	if (off > sizeof(struct ip6_hdr)) {
1453 		size_t l;
1454 		struct ip6_hdr nip6;
1455 
1456 		l = off - sizeof(struct ip6_hdr);
1457 		m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
1458 		m_adj(m, l);
1459 		l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1460 		if (m->m_len < l) {
1461 			if ((m = m_pullup(m, l)) == NULL)
1462 				return;
1463 		}
1464 		bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
1465 	} else /* off == sizeof(struct ip6_hdr) */ {
1466 		size_t l;
1467 		l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1468 		if (m->m_len < l) {
1469 			if ((m = m_pullup(m, l)) == NULL)
1470 				return;
1471 		}
1472 	}
1473 	plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
1474 	ip6 = mtod(m, struct ip6_hdr *);
1475 	ip6->ip6_nxt = IPPROTO_ICMPV6;
1476 	icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1477 	type = icmp6->icmp6_type; /* keep type for statistics */
1478 	code = icmp6->icmp6_code; /* ditto. */
1479 
1480 	t = ip6->ip6_dst;
1481 	/*
1482 	 * ip6_input() drops a packet if its src is multicast.
1483 	 * So, the src is never multicast.
1484 	 */
1485 	ip6->ip6_dst = ip6->ip6_src;
1486 
1487 	/* XXX hack for link-local addresses */
1488 	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
1489 		ip6->ip6_dst.s6_addr16[1] =
1490 			htons(m->m_pkthdr.rcvif->if_index);
1491 	if (IN6_IS_ADDR_LINKLOCAL(&t))
1492 		t.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
1493 
1494 #ifdef COMPAT_RFC1885
1495 	/*
1496 	 * xxx guess MTU
1497 	 * RFC 1885 requires that echo reply should be truncated if it
1498 	 * does not fit in with (return) path MTU, but the description was
1499 	 * removed in the new spec.
1500 	 */
1501 	if (icmp6_reflect_rt.ro_rt == 0 ||
1502 	    ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) {
1503 		if (icmp6_reflect_rt.ro_rt) {
1504 			icmp6_reflect_rt.ro_rt = 0;
1505 		}
1506 		bzero(sin6, sizeof(*sin6));
1507 		sin6->sin6_family = PF_INET6;
1508 		sin6->sin6_len = sizeof(struct sockaddr_in6);
1509 		sin6->sin6_addr = ip6->ip6_dst;
1510 
1511 		rtalloc((struct route *)&icmp6_reflect_rt.ro_rt);
1512 	}
1513 
1514 	if (icmp6_reflect_rt.ro_rt == 0)
1515 		goto bad;
1516 
1517 	if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST)
1518 	    && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu)
1519 		mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu;
1520 
1521 	if (mtu < m->m_pkthdr.len) {
1522 		plen -= (m->m_pkthdr.len - mtu);
1523 		m_adj(m, mtu - m->m_pkthdr.len);
1524 	}
1525 #endif
1526 	/*
1527 	 * If the incoming packet was addressed directly to us(i.e. unicast),
1528 	 * use dst as the src for the reply.
1529 	 * The IN6_IFF_NOTREADY case would be VERY rare, but is possible when
1530 	 * (for example) when we encounter an error while forwarding procedure
1531 	 * destined to a duplicated address of ours.
1532 	 */
1533 	for (ia = in6_ifaddr; ia; ia = ia->ia_next)
1534 		if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
1535 		    (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
1536 			src = &t;
1537 			break;
1538 		}
1539 	if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
1540 		/*
1541 		 * This is the case if the dst is our link-local address
1542 		 * and the sender is also ourseleves.
1543 		 */
1544 		src = &t;
1545 	}
1546 
1547 	if (src == 0)
1548 		/*
1549 		 * This case matches to multicasts, our anycast, or unicasts
1550 		 * that we do not own. Select a source address which has the
1551 		 * same scope.
1552 		 * XXX: for (non link-local) multicast addresses, this might
1553 		 * not be a good choice.
1554 		 */
1555 		if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
1556 			src = &IA6_SIN6(ia)->sin6_addr;
1557 
1558 	if (src == 0)
1559 		goto bad;
1560 
1561 	ip6->ip6_src = *src;
1562 
1563 	ip6->ip6_flow = 0;
1564 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1565 	ip6->ip6_vfc |= IPV6_VERSION;
1566 	ip6->ip6_nxt = IPPROTO_ICMPV6;
1567 	if (m->m_pkthdr.rcvif) {
1568 		/* XXX: This may not be the outgoing interface */
1569 		ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
1570 	}
1571 
1572 	icmp6->icmp6_cksum = 0;
1573 	icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1574 					sizeof(struct ip6_hdr), plen);
1575 
1576 	/*
1577 	 * xxx option handling
1578 	 */
1579 
1580 	m->m_flags &= ~(M_BCAST|M_MCAST);
1581 #ifdef IPSEC
1582 	/* Don't lookup socket */
1583 	ipsec_setsocket(m, NULL);
1584 #endif /*IPSEC*/
1585 
1586 #ifdef COMPAT_RFC1885
1587 	ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif);
1588 #else
1589 	ip6_output(m, NULL, NULL, 0, NULL, &outif);
1590 #endif
1591 	if (outif)
1592 		icmp6_ifoutstat_inc(outif, type, code);
1593 
1594 	return;
1595 
1596  bad:
1597 	m_freem(m);
1598 	return;
1599 }
1600 
1601 void
1602 icmp6_fasttimo()
1603 {
1604 	mld6_fasttimeo();
1605 }
1606 
1607 static const char *
1608 icmp6_redirect_diag(src6, dst6, tgt6)
1609 	struct in6_addr *src6;
1610 	struct in6_addr *dst6;
1611 	struct in6_addr *tgt6;
1612 {
1613 	static char buf[1024];
1614 	snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
1615 		ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
1616 	return buf;
1617 }
1618 
1619 void
1620 icmp6_redirect_input(m, off)
1621 	register struct mbuf *m;
1622 	int off;
1623 {
1624 	struct ifnet *ifp = m->m_pkthdr.rcvif;
1625 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1626 	struct nd_redirect *nd_rd;
1627 	int icmp6len = ntohs(ip6->ip6_plen);
1628 	char *lladdr = NULL;
1629 	int lladdrlen = 0;
1630 	u_char *redirhdr = NULL;
1631 	int redirhdrlen = 0;
1632 	struct rtentry *rt = NULL;
1633 	int is_router;
1634 	int is_onlink;
1635 	struct in6_addr src6 = ip6->ip6_src;
1636 	struct in6_addr redtgt6;
1637 	struct in6_addr reddst6;
1638 	union nd_opts ndopts;
1639 
1640 	if (!m || !ifp)
1641 		return;
1642 
1643 	/* XXX if we are router, we don't update route by icmp6 redirect */
1644 	if (ip6_forwarding)
1645 		goto freeit;
1646 	if (!icmp6_rediraccept)
1647 		goto freeit;
1648 
1649 #ifndef PULLDOWN_TEST
1650 	IP6_EXTHDR_CHECK(m, off, icmp6len,);
1651 	nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
1652 #else
1653 	IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
1654 	if (nd_rd == NULL) {
1655 		icmp6stat.icp6s_tooshort++;
1656 		return;
1657 	}
1658 #endif
1659 	redtgt6 = nd_rd->nd_rd_target;
1660 	reddst6 = nd_rd->nd_rd_dst;
1661 
1662 	if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1663 		redtgt6.s6_addr16[1] = htons(ifp->if_index);
1664 	if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
1665 		reddst6.s6_addr16[1] = htons(ifp->if_index);
1666 
1667 	/* validation */
1668 	if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
1669 		log(LOG_ERR,
1670 			"ICMP6 redirect sent from %s rejected; "
1671 			"must be from linklocal\n", ip6_sprintf(&src6));
1672 		goto freeit;
1673 	}
1674 	if (ip6->ip6_hlim != 255) {
1675 		log(LOG_ERR,
1676 			"ICMP6 redirect sent from %s rejected; "
1677 			"hlim=%d (must be 255)\n",
1678 			ip6_sprintf(&src6), ip6->ip6_hlim);
1679 		goto freeit;
1680 	}
1681     {
1682 	/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
1683 	struct sockaddr_in6 sin6;
1684 	struct in6_addr *gw6;
1685 
1686 	bzero(&sin6, sizeof(sin6));
1687 	sin6.sin6_family = AF_INET6;
1688 	sin6.sin6_len = sizeof(struct sockaddr_in6);
1689 	bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
1690 	rt = rtalloc1((struct sockaddr *)&sin6, 0);
1691 	if (rt) {
1692 		gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
1693 		if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
1694 			log(LOG_ERR,
1695 				"ICMP6 redirect rejected; "
1696 				"not equal to gw-for-src=%s (must be same): "
1697 				"%s\n",
1698 				ip6_sprintf(gw6),
1699 				icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1700 			RTFREE(rt);
1701 			goto freeit;
1702 		}
1703 	} else {
1704 		log(LOG_ERR,
1705 			"ICMP6 redirect rejected; "
1706 			"no route found for redirect dst: %s\n",
1707 			icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1708 		goto freeit;
1709 	}
1710 	RTFREE(rt);
1711 	rt = NULL;
1712     }
1713 	if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
1714 		log(LOG_ERR,
1715 			"ICMP6 redirect rejected; "
1716 			"redirect dst must be unicast: %s\n",
1717 			icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1718 		goto freeit;
1719 	}
1720 
1721 	is_router = is_onlink = 0;
1722 	if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1723 		is_router = 1;	/* router case */
1724 	if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
1725 		is_onlink = 1;	/* on-link destination case */
1726 	if (!is_router && !is_onlink) {
1727 		log(LOG_ERR,
1728 			"ICMP6 redirect rejected; "
1729 			"neither router case nor onlink case: %s\n",
1730 			icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1731 		goto freeit;
1732 	}
1733 	/* validation passed */
1734 
1735 	icmp6len -= sizeof(*nd_rd);
1736 	nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
1737 	if (nd6_options(&ndopts) < 0) {
1738 		log(LOG_INFO, "icmp6_redirect_input: "
1739 			"invalid ND option, rejected: %s\n",
1740 			icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1741 		goto freeit;
1742 	}
1743 
1744 	if (ndopts.nd_opts_tgt_lladdr) {
1745 		lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
1746 		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
1747 	}
1748 
1749 	if (ndopts.nd_opts_rh) {
1750 		redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
1751 		redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
1752 	}
1753 
1754 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
1755 		log(LOG_INFO,
1756 			"icmp6_redirect_input: lladdrlen mismatch for %s "
1757 			"(if %d, icmp6 packet %d): %s\n",
1758 			ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
1759 			icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
1760 	}
1761 
1762 	/* RFC 2461 8.3 */
1763 	nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
1764 			 is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
1765 
1766 	if (!is_onlink) {	/* better router case. perform rtredirect. */
1767 		/* perform rtredirect */
1768 		struct sockaddr_in6 sdst;
1769 		struct sockaddr_in6 sgw;
1770 		struct sockaddr_in6 ssrc;
1771 
1772 		bzero(&sdst, sizeof(sdst));
1773 		bzero(&sgw, sizeof(sgw));
1774 		bzero(&ssrc, sizeof(ssrc));
1775 		sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
1776 		sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
1777 			sizeof(struct sockaddr_in6);
1778 		bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
1779 		bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
1780 		bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
1781 		rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
1782 			   (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
1783 			   (struct sockaddr *)&ssrc,
1784 			   (struct rtentry **)NULL
1785 			   );
1786 	}
1787 	/* finally update cached route in each socket via pfctlinput */
1788     {
1789 	struct sockaddr_in6 sdst;
1790 #if 1
1791 #else
1792 	struct ip6protosw *pr;
1793 #endif
1794 
1795 	bzero(&sdst, sizeof(sdst));
1796 	sdst.sin6_family = AF_INET6;
1797 	sdst.sin6_len = sizeof(struct sockaddr_in6);
1798 	bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
1799 #if 1
1800 	pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
1801 #else
1802 	/*
1803 	 * do not use pfctlinput() here, we have different prototype for
1804 	 * xx_ctlinput() in ip6proto.
1805 	 */
1806 	for (pr = (struct ip6protosw *)inet6domain.dom_protosw;
1807 	     pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW;
1808 	     pr++) {
1809 		if (pr->pr_ctlinput) {
1810 			(*pr->pr_ctlinput)(PRC_REDIRECT_HOST,
1811 				(struct sockaddr *)&sdst, NULL, NULL, 0);
1812 		}
1813 	}
1814 #endif
1815 #ifdef IPSEC
1816 	key_sa_routechange((struct sockaddr *)&sdst);
1817 #endif
1818     }
1819 
1820  freeit:
1821 	m_freem(m);
1822 }
1823 
1824 void
1825 icmp6_redirect_output(m0, rt)
1826 	struct mbuf *m0;
1827 	struct rtentry *rt;
1828 {
1829 	struct ifnet *ifp;	/* my outgoing interface */
1830 	struct in6_addr *ifp_ll6;
1831 	struct in6_addr *router_ll6;
1832 	struct ip6_hdr *sip6;	/* m0 as struct ip6_hdr */
1833 	struct mbuf *m = NULL;	/* newly allocated one */
1834 	struct ip6_hdr *ip6;	/* m as struct ip6_hdr */
1835 	struct nd_redirect *nd_rd;
1836 	size_t maxlen;
1837 	u_char *p;
1838 	struct ifnet *outif = NULL;
1839 
1840 	/* if we are not router, we don't send icmp6 redirect */
1841 	if (!ip6_forwarding || ip6_accept_rtadv)
1842 		goto fail;
1843 
1844 	/* sanity check */
1845 	if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
1846 		goto fail;
1847 
1848 	/*
1849 	 * Address check:
1850 	 *  the source address must identify a neighbor, and
1851 	 *  the destination address must not be a multicast address
1852 	 *  [RFC 2461, sec 8.2]
1853 	 */
1854 	sip6 = mtod(m0, struct ip6_hdr *);
1855 	if (nd6_is_addr_neighbor(&sip6->ip6_src, ifp) == 0)
1856 		goto fail;
1857 	if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
1858 		goto fail;	/* what should we do here? */
1859 
1860 	/* rate limit */
1861 	if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
1862 		goto fail;
1863 
1864 	/*
1865 	 * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
1866 	 * we almost always ask for an mbuf cluster for simplicity.
1867 	 * (MHLEN < IPV6_MMTU is almost always true)
1868 	 */
1869 #if IPV6_MMTU >= MCLBYTES
1870 # error assumption failed about IPV6_MMTU and MCLBYTES
1871 #endif
1872 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
1873 	if (m && IPV6_MMTU >= MHLEN)
1874 		MCLGET(m, M_DONTWAIT);
1875 	if (!m)
1876 		goto fail;
1877 	maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
1878 	maxlen = min(IPV6_MMTU, maxlen);
1879 	/* just for safety */
1880 	if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
1881 	    ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
1882 		goto fail;
1883 	}
1884 
1885 	{
1886 		/* get ip6 linklocal address for ifp(my outgoing interface). */
1887 		struct in6_ifaddr *ia;
1888 		if ((ia = in6ifa_ifpforlinklocal(ifp,
1889 						 IN6_IFF_NOTREADY|
1890 						 IN6_IFF_ANYCAST)) == NULL)
1891 			goto fail;
1892 		ifp_ll6 = &ia->ia_addr.sin6_addr;
1893 	}
1894 
1895 	/* get ip6 linklocal address for the router. */
1896 	if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
1897 		struct sockaddr_in6 *sin6;
1898 		sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
1899 		router_ll6 = &sin6->sin6_addr;
1900 		if (!IN6_IS_ADDR_LINKLOCAL(router_ll6))
1901 			router_ll6 = (struct in6_addr *)NULL;
1902 	} else
1903 		router_ll6 = (struct in6_addr *)NULL;
1904 
1905 	/* ip6 */
1906 	ip6 = mtod(m, struct ip6_hdr *);
1907 	ip6->ip6_flow = 0;
1908 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1909 	ip6->ip6_vfc |= IPV6_VERSION;
1910 	/* ip6->ip6_plen will be set later */
1911 	ip6->ip6_nxt = IPPROTO_ICMPV6;
1912 	ip6->ip6_hlim = 255;
1913 	/* ip6->ip6_src must be linklocal addr for my outgoing if. */
1914 	bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
1915 	bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
1916 
1917 	/* ND Redirect */
1918 	nd_rd = (struct nd_redirect *)(ip6 + 1);
1919 	nd_rd->nd_rd_type = ND_REDIRECT;
1920 	nd_rd->nd_rd_code = 0;
1921 	nd_rd->nd_rd_reserved = 0;
1922 	if (rt->rt_flags & RTF_GATEWAY) {
1923 		/*
1924 		 * nd_rd->nd_rd_target must be a link-local address in
1925 		 * better router cases.
1926 		 */
1927 		if (!router_ll6)
1928 			goto fail;
1929 		bcopy(router_ll6, &nd_rd->nd_rd_target,
1930 		      sizeof(nd_rd->nd_rd_target));
1931 		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1932 		      sizeof(nd_rd->nd_rd_dst));
1933 	} else {
1934 		/* make sure redtgt == reddst */
1935 		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
1936 		      sizeof(nd_rd->nd_rd_target));
1937 		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1938 		      sizeof(nd_rd->nd_rd_dst));
1939 	}
1940 
1941 	p = (u_char *)(nd_rd + 1);
1942 
1943 	if (!router_ll6)
1944 		goto nolladdropt;
1945 
1946     {
1947 	/* target lladdr option */
1948 	struct rtentry *rt_router = NULL;
1949 	int len;
1950 	struct sockaddr_dl *sdl;
1951 	struct nd_opt_hdr *nd_opt;
1952 	char *lladdr;
1953 
1954 	rt_router = nd6_lookup(router_ll6, 0, ifp);
1955 	if (!rt_router)
1956 		goto nolladdropt;
1957 	len = sizeof(*nd_opt) + ifp->if_addrlen;
1958 	len = (len + 7) & ~7;	/*round by 8*/
1959 	/* safety check */
1960 	if (len + (p - (u_char *)ip6) > maxlen)
1961 		goto nolladdropt;
1962 	if (!(rt_router->rt_flags & RTF_GATEWAY) &&
1963 	    (rt_router->rt_flags & RTF_LLINFO) &&
1964 	    (rt_router->rt_gateway->sa_family == AF_LINK) &&
1965 	    (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) &&
1966 	    sdl->sdl_alen) {
1967 		nd_opt = (struct nd_opt_hdr *)p;
1968 		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1969 		nd_opt->nd_opt_len = len >> 3;
1970 		lladdr = (char *)(nd_opt + 1);
1971 		bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
1972 		p += len;
1973 	}
1974     }
1975 nolladdropt:;
1976 
1977 	m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1978 
1979 	/* just to be safe */
1980 	if (m0->m_flags & M_DECRYPTED)
1981 		goto noredhdropt;
1982 	if (p - (u_char *)ip6 > maxlen)
1983 		goto noredhdropt;
1984 
1985     {
1986 	/* redirected header option */
1987 	int len;
1988 	struct nd_opt_rd_hdr *nd_opt_rh;
1989 
1990 	/*
1991 	 * compute the maximum size for icmp6 redirect header option.
1992 	 * XXX room for auth header?
1993 	 */
1994 	len = maxlen - (p - (u_char *)ip6);
1995 	len &= ~7;
1996 
1997 	/* This is just for simplicity. */
1998 	if (m0->m_pkthdr.len != m0->m_len) {
1999 		if (m0->m_next) {
2000 			m_freem(m0->m_next);
2001 			m0->m_next = NULL;
2002 		}
2003 		m0->m_pkthdr.len = m0->m_len;
2004 	}
2005 
2006 	/*
2007 	 * Redirected header option spec (RFC2461 4.6.3) talks nothing
2008 	 * about padding/truncate rule for the original IP packet.
2009 	 * From the discussion on IPv6imp in Feb 1999, the consensus was:
2010 	 * - "attach as much as possible" is the goal
2011 	 * - pad if not aligned (original size can be guessed by original
2012 	 *   ip6 header)
2013 	 * Following code adds the padding if it is simple enough,
2014 	 * and truncates if not.
2015 	 */
2016 	if (m0->m_next || m0->m_pkthdr.len != m0->m_len)
2017 		panic("assumption failed in %s:%d\n", __FILE__, __LINE__);
2018 
2019 	if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
2020 		/* not enough room, truncate */
2021 		m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2022 	} else {
2023 		/* enough room, pad or truncate */
2024 		size_t extra;
2025 
2026 		extra = m0->m_pkthdr.len % 8;
2027 		if (extra) {
2028 			/* pad if easy enough, truncate if not */
2029 			if (8 - extra <= M_TRAILINGSPACE(m0)) {
2030 				/* pad */
2031 				m0->m_len += (8 - extra);
2032 				m0->m_pkthdr.len += (8 - extra);
2033 			} else {
2034 				/* truncate */
2035 				m0->m_pkthdr.len -= extra;
2036 				m0->m_len -= extra;
2037 			}
2038 		}
2039 		len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
2040 		m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2041 	}
2042 
2043 	nd_opt_rh = (struct nd_opt_rd_hdr *)p;
2044 	bzero(nd_opt_rh, sizeof(*nd_opt_rh));
2045 	nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
2046 	nd_opt_rh->nd_opt_rh_len = len >> 3;
2047 	p += sizeof(*nd_opt_rh);
2048 	m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2049 
2050 	/* connect m0 to m */
2051 	m->m_next = m0;
2052 	m->m_pkthdr.len = m->m_len + m0->m_len;
2053     }
2054 noredhdropt:;
2055 
2056 	if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
2057 		sip6->ip6_src.s6_addr16[1] = 0;
2058 	if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
2059 		sip6->ip6_dst.s6_addr16[1] = 0;
2060 #if 0
2061 	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
2062 		ip6->ip6_src.s6_addr16[1] = 0;
2063 	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
2064 		ip6->ip6_dst.s6_addr16[1] = 0;
2065 #endif
2066 	if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
2067 		nd_rd->nd_rd_target.s6_addr16[1] = 0;
2068 	if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
2069 		nd_rd->nd_rd_dst.s6_addr16[1] = 0;
2070 
2071 	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
2072 
2073 	nd_rd->nd_rd_cksum = 0;
2074 	nd_rd->nd_rd_cksum
2075 		= in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
2076 
2077 	/* send the packet to outside... */
2078 #ifdef IPSEC
2079 	/* Don't lookup socket */
2080 	ipsec_setsocket(m, NULL);
2081 #endif /*IPSEC*/
2082 	ip6_output(m, NULL, NULL, 0, NULL, &outif);
2083 	if (outif) {
2084 		icmp6_ifstat_inc(outif, ifs6_out_msg);
2085 		icmp6_ifstat_inc(outif, ifs6_out_redirect);
2086 	}
2087 	icmp6stat.icp6s_outhist[ND_REDIRECT]++;
2088 
2089 	return;
2090 
2091 fail:
2092 	if (m)
2093 		m_freem(m);
2094 	if (m0)
2095 		m_freem(m0);
2096 }
2097 
2098 /*
2099  * ICMPv6 socket option processing.
2100  */
2101 int
2102 icmp6_ctloutput(op, so, level, optname, mp)
2103 	int op;
2104 	struct socket *so;
2105 	int level, optname;
2106 	struct mbuf **mp;
2107 {
2108 	register struct in6pcb *in6p = sotoin6pcb(so);
2109 	register struct mbuf *m = *mp;
2110 	int error = 0;
2111 
2112 	if (level != IPPROTO_ICMPV6) {
2113 		error = EINVAL;
2114 		if (op == PRCO_SETOPT && m)
2115 			(void)m_free(m);
2116 	} else switch(op) {
2117 	 case PRCO_SETOPT:
2118 		 switch (optname) {
2119 		  case ICMP6_FILTER:
2120 		  {
2121 			  struct icmp6_filter *p;
2122 
2123 			  p = mtod(m, struct icmp6_filter *);
2124 			  if (!p || !in6p->in6p_icmp6filt) {
2125 				  error = EINVAL;
2126 				  break;
2127 			  }
2128 			  bcopy(p, in6p->in6p_icmp6filt,
2129 				sizeof(struct icmp6_filter));
2130 			  error = 0;
2131 			  break;
2132 		  }
2133 
2134 		  default:
2135 			  error = ENOPROTOOPT;
2136 			  break;
2137 		 }
2138 		 if (m)
2139 			 (void)m_free(m);
2140 		 break;
2141 
2142 	 case PRCO_GETOPT:
2143 		 switch (optname) {
2144 		  case ICMP6_FILTER:
2145 		  {
2146 			  struct icmp6_filter *p;
2147 
2148 			  if (!in6p->in6p_icmp6filt) {
2149 				  error = EINVAL;
2150 				  break;
2151 			  }
2152 			  *mp = m = m_get(M_WAIT, MT_SOOPTS);
2153 			  m->m_len = sizeof(struct icmp6_filter);
2154 			  p = mtod(m, struct icmp6_filter *);
2155 			  bcopy(in6p->in6p_icmp6filt, p,
2156 				sizeof(struct icmp6_filter));
2157 			  error = 0;
2158 			  break;
2159 		  }
2160 
2161 		  default:
2162 			  error = ENOPROTOOPT;
2163 			  break;
2164 		 }
2165 		 break;
2166 	}
2167 
2168 	return(error);
2169 }
2170 
2171 /*
2172  * Perform rate limit check.
2173  * Returns 0 if it is okay to send the icmp6 packet.
2174  * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
2175  * limitation.
2176  *
2177  * XXX per-destination/type check necessary?
2178  */
2179 static int
2180 icmp6_ratelimit(dst, type, code)
2181 	const struct in6_addr *dst;	/* not used at this moment */
2182 	const int type;			/* not used at this moment */
2183 	const int code;			/* not used at this moment */
2184 {
2185 	static struct timeval icmp6errratelim_last;
2186 
2187 	/*
2188 	 * ratecheck() returns true if it is okay to send.  We return
2189 	 * true if it is not okay to send.
2190 	 */
2191 	return (ratecheck(&icmp6errratelim_last, &icmp6errratelim) == 0);
2192 }
2193 
2194 static struct rtentry *
2195 icmp6_mtudisc_clone(dst)
2196 	struct sockaddr *dst;
2197 {
2198 	struct rtentry *rt;
2199 	int    error;
2200 
2201 	rt = rtalloc1(dst, 1);
2202 	if (rt == 0)
2203 		return NULL;
2204 
2205 	/* If we didn't get a host route, allocate one */
2206 	if ((rt->rt_flags & RTF_HOST) == 0) {
2207 		struct rtentry *nrt;
2208 
2209 		error = rtrequest((int) RTM_ADD, dst,
2210 		    (struct sockaddr *) rt->rt_gateway,
2211 		    (struct sockaddr *) 0,
2212 		    RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
2213 		if (error) {
2214 			rtfree(rt);
2215 			rtfree(nrt);
2216 			return NULL;
2217 		}
2218 		nrt->rt_rmx = rt->rt_rmx;
2219 		rtfree(rt);
2220 		rt = nrt;
2221 	}
2222 	error = rt_timer_add(rt, icmp6_mtudisc_timeout,
2223 			icmp6_mtudisc_timeout_q);
2224 	if (error) {
2225 		rtfree(rt);
2226 		return NULL;
2227 	}
2228 
2229 	return rt;	/* caller need to call rtfree() */
2230 }
2231 
2232 static void
2233 icmp6_mtudisc_timeout(rt, r)
2234 	struct rtentry *rt;
2235 	struct rttimer *r;
2236 {
2237 	if (rt == NULL)
2238 		panic("icmp6_mtudisc_timeout: bad route to timeout");
2239 	if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
2240 	    (RTF_DYNAMIC | RTF_HOST)) {
2241 		rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
2242 		    rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
2243 	} else {
2244 		if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
2245 			rt->rt_rmx.rmx_mtu = 0;
2246 		}
2247 	}
2248 }
2249 
2250 #include <vm/vm.h>
2251 #include <sys/sysctl.h>
2252 int
2253 icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
2254 	int *name;
2255 	u_int namelen;
2256 	void *oldp;
2257 	size_t *oldlenp;
2258 	void *newp;
2259 	size_t newlen;
2260 {
2261 
2262 	/* All sysctl names at this level are terminal. */
2263 	if (namelen != 1)
2264 		return ENOTDIR;
2265 
2266 	switch (name[0]) {
2267 
2268 	case ICMPV6CTL_REDIRACCEPT:
2269 		return sysctl_int(oldp, oldlenp, newp, newlen,
2270 				&icmp6_rediraccept);
2271 	case ICMPV6CTL_REDIRTIMEOUT:
2272 		return sysctl_int(oldp, oldlenp, newp, newlen,
2273 				&icmp6_redirtimeout);
2274 	case ICMPV6CTL_STATS:
2275 		return sysctl_rdstruct(oldp, oldlenp, newp,
2276 				&icmp6stat, sizeof(icmp6stat));
2277 	case ICMPV6CTL_ERRRATELIMIT:
2278 	    {
2279 		int rate_usec, error, s;
2280 
2281 		/*
2282 		 * The sysctl specifies the rate in usec-between-icmp,
2283 		 * so we must convert from/to a timeval.
2284 		 */
2285 		rate_usec = (icmp6errratelim.tv_sec * 1000000) +
2286 		    icmp6errratelim.tv_usec;
2287 		error = sysctl_int(oldp, oldlenp, newp, newlen, &rate_usec);
2288 		if (error)
2289 			return (error);
2290 		s = splsoftnet();
2291 		icmp6errratelim.tv_sec = rate_usec / 1000000;
2292 		icmp6errratelim.tv_usec = rate_usec % 1000000;
2293 		splx(s);
2294 
2295 		return (0);
2296 	    }
2297 	case ICMPV6CTL_ND6_PRUNE:
2298 		return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_prune);
2299 	case ICMPV6CTL_ND6_DELAY:
2300 		return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_delay);
2301 	case ICMPV6CTL_ND6_UMAXTRIES:
2302 		return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_umaxtries);
2303 	case ICMPV6CTL_ND6_MMAXTRIES:
2304 		return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_mmaxtries);
2305 	case ICMPV6CTL_ND6_USELOOPBACK:
2306 		return sysctl_int(oldp, oldlenp, newp, newlen,
2307 				&nd6_useloopback);
2308 	case ICMPV6CTL_NODEINFO:
2309 		return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6_nodeinfo);
2310 	default:
2311 		return ENOPROTOOPT;
2312 	}
2313 	/* NOTREACHED */
2314 }
2315