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