icmp6.c revision 105199
1118611Snjl/*	$FreeBSD: head/sys/netinet6/icmp6.c 105199 2002-10-16 02:25:05Z sam $	*/
2118611Snjl/*	$KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $	*/
3118611Snjl
4118611Snjl/*
5118611Snjl * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6118611Snjl * All rights reserved.
7118611Snjl *
8118611Snjl * Redistribution and use in source and binary forms, with or without
9118611Snjl * modification, are permitted provided that the following conditions
10118611Snjl * are met:
11118611Snjl * 1. Redistributions of source code must retain the above copyright
12202771Sjkim *    notice, this list of conditions and the following disclaimer.
13118611Snjl * 2. Redistributions in binary form must reproduce the above copyright
14118611Snjl *    notice, this list of conditions and the following disclaimer in the
15118611Snjl *    documentation and/or other materials provided with the distribution.
16118611Snjl * 3. Neither the name of the project nor the names of its contributors
17118611Snjl *    may be used to endorse or promote products derived from this software
18118611Snjl *    without specific prior written permission.
19118611Snjl *
20118611Snjl * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21118611Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22118611Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23118611Snjl * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24118611Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25118611Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26118611Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27118611Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28118611Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29118611Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30118611Snjl * SUCH DAMAGE.
31118611Snjl */
32118611Snjl
33118611Snjl/*
34118611Snjl * Copyright (c) 1982, 1986, 1988, 1993
35118611Snjl *	The Regents of the University of California.  All rights reserved.
36118611Snjl *
37118611Snjl * Redistribution and use in source and binary forms, with or without
38118611Snjl * modification, are permitted provided that the following conditions
39118611Snjl * are met:
40118611Snjl * 1. Redistributions of source code must retain the above copyright
41118611Snjl *    notice, this list of conditions and the following disclaimer.
42118611Snjl * 2. Redistributions in binary form must reproduce the above copyright
43118611Snjl *    notice, this list of conditions and the following disclaimer in the
44118611Snjl *    documentation and/or other materials provided with the distribution.
45118611Snjl * 3. All advertising materials mentioning features or use of this software
46118611Snjl *    must display the following acknowledgement:
47118611Snjl *	This product includes software developed by the University of
48118611Snjl *	California, Berkeley and its contributors.
49118611Snjl * 4. Neither the name of the University nor the names of its contributors
50118611Snjl *    may be used to endorse or promote products derived from this software
51118611Snjl *    without specific prior written permission.
52118611Snjl *
53118611Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54118611Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55118611Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56118611Snjl * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57118611Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58118611Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59118611Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60118611Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61118611Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62118611Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63118611Snjl * SUCH DAMAGE.
64118611Snjl *
65118611Snjl *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
66118611Snjl */
67118611Snjl
68118611Snjl#include "opt_inet.h"
69118611Snjl#include "opt_inet6.h"
70118611Snjl#include "opt_ipsec.h"
71118611Snjl
72118611Snjl#include <sys/param.h>
73118611Snjl#include <sys/domain.h>
74118611Snjl#include <sys/kernel.h>
75118611Snjl#include <sys/lock.h>
76118611Snjl#include <sys/malloc.h>
77118611Snjl#include <sys/mbuf.h>
78118611Snjl#include <sys/protosw.h>
79118611Snjl#include <sys/signalvar.h>
80118611Snjl#include <sys/socket.h>
81118611Snjl#include <sys/socketvar.h>
82118611Snjl#include <sys/sx.h>
83118611Snjl#include <sys/syslog.h>
84118611Snjl#include <sys/systm.h>
85118611Snjl#include <sys/time.h>
86118611Snjl
87118611Snjl#include <net/if.h>
88118611Snjl#include <net/if_dl.h>
89118611Snjl#include <net/if_types.h>
90118611Snjl#include <net/route.h>
91118611Snjl
92118611Snjl#include <netinet/in.h>
93118611Snjl#include <netinet/in_pcb.h>
94118611Snjl#include <netinet/in_var.h>
95118611Snjl#include <netinet/ip6.h>
96118611Snjl#include <netinet/icmp6.h>
97118611Snjl#include <netinet6/in6_ifattach.h>
98118611Snjl#include <netinet6/in6_pcb.h>
99118611Snjl#include <netinet6/ip6protosw.h>
100118611Snjl#include <netinet6/ip6_var.h>
101118611Snjl#include <netinet6/mld6_var.h>
102118611Snjl#include <netinet6/nd6.h>
103118611Snjl
104118611Snjl#ifdef IPSEC
105118611Snjl#include <netinet6/ipsec.h>
106118611Snjl#include <netkey/key.h>
107118611Snjl#endif
108118611Snjl
109118611Snjl#ifdef FAST_IPSEC
110118611Snjl#include <netipsec/ipsec.h>
111118611Snjl#include <netipsec/key.h>
112118611Snjl#define	IPSEC
113118611Snjl#endif
114118611Snjl
115118611Snjl#include <net/net_osdep.h>
116118611Snjl
117118611Snjl#ifdef HAVE_NRL_INPCB
118151937Sjkim/* inpcb members */
119118611Snjl#define in6pcb		inpcb
120118611Snjl#define in6p_laddr	inp_laddr6
121118611Snjl#define in6p_faddr	inp_faddr6
122118611Snjl#define in6p_icmp6filt	inp_icmp6filt
123151937Sjkim#define in6p_route	inp_route
124118611Snjl#define in6p_socket	inp_socket
125151937Sjkim#define in6p_flags	inp_flags
126151937Sjkim#define in6p_moptions	inp_moptions6
127151937Sjkim#define in6p_outputopts	inp_outputopts6
128151937Sjkim#define in6p_ip6	inp_ipv6
129151937Sjkim#define in6p_flowinfo	inp_flowinfo
130193529Sjkim#define in6p_sp		inp_sp
131193529Sjkim#define in6p_next	inp_next
132193529Sjkim#define in6p_prev	inp_prev
133193529Sjkim/* macro names */
134193529Sjkim#define sotoin6pcb	sotoinpcb
135193529Sjkim/* function names */
136193529Sjkim#define in6_pcbdetach	in_pcbdetach
137193529Sjkim#define in6_rtchange	in_rtchange
138193529Sjkim
139193529Sjkim/*
140193529Sjkim * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from
141193529Sjkim * others...
142193529Sjkim */
143193529Sjkim#define in6p_ip6_nxt	inp_ipv6.ip6_nxt
144193529Sjkim#endif
145193529Sjkim
146193529Sjkimextern struct domain inet6domain;
147193529Sjkim
148193529Sjkimstruct icmp6stat icmp6stat;
149193529Sjkim
150118611Snjlextern struct inpcbhead ripcb;
151118611Snjlextern int icmp6errppslim;
152118611Snjlstatic int icmp6errpps_count = 0;
153118611Snjlstatic struct timeval icmp6errppslim_last;
154118611Snjlextern int icmp6_nodeinfo;
155118611Snjl
156118611Snjlstatic void icmp6_errcount __P((struct icmp6errstat *, int, int));
157118611Snjlstatic int icmp6_rip6_input __P((struct mbuf **, int));
158118611Snjlstatic int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
159118611Snjlstatic const char *icmp6_redirect_diag __P((struct in6_addr *,
160118611Snjl	struct in6_addr *, struct in6_addr *));
161118611Snjl#ifndef HAVE_PPSRATECHECK
162118611Snjlstatic int ppsratecheck __P((struct timeval *, int *, int));
163118611Snjl#endif
164151937Sjkimstatic struct mbuf *ni6_input __P((struct mbuf *, int));
165118611Snjlstatic struct mbuf *ni6_nametodns __P((const char *, int, int));
166118611Snjlstatic int ni6_dnsmatch __P((const char *, int, const char *, int));
167118611Snjlstatic int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
168118611Snjl			  struct ifnet **, char *));
169118611Snjlstatic int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
170118611Snjl				struct ifnet *, int));
171118611Snjlstatic int icmp6_notify_error __P((struct mbuf *, int, int, int));
172202771Sjkim
173118611Snjl#ifdef COMPAT_RFC1885
174118611Snjlstatic struct route_in6 icmp6_reflect_rt;
175118611Snjl#endif
176118611Snjl
177118611Snjl
178118611Snjlvoid
179118611Snjlicmp6_init()
180202771Sjkim{
181202771Sjkim	mld6_init();
182202771Sjkim}
183202771Sjkim
184118611Snjlstatic void
185118611Snjlicmp6_errcount(stat, type, code)
186118611Snjl	struct icmp6errstat *stat;
187118611Snjl	int type, code;
188118611Snjl{
189118611Snjl	switch (type) {
190118611Snjl	case ICMP6_DST_UNREACH:
191118611Snjl		switch (code) {
192118611Snjl		case ICMP6_DST_UNREACH_NOROUTE:
193118611Snjl			stat->icp6errs_dst_unreach_noroute++;
194118611Snjl			return;
195118611Snjl		case ICMP6_DST_UNREACH_ADMIN:
196118611Snjl			stat->icp6errs_dst_unreach_admin++;
197118611Snjl			return;
198118611Snjl		case ICMP6_DST_UNREACH_BEYONDSCOPE:
199118611Snjl			stat->icp6errs_dst_unreach_beyondscope++;
200118611Snjl			return;
201118611Snjl		case ICMP6_DST_UNREACH_ADDR:
202118611Snjl			stat->icp6errs_dst_unreach_addr++;
203118611Snjl			return;
204118611Snjl		case ICMP6_DST_UNREACH_NOPORT:
205118611Snjl			stat->icp6errs_dst_unreach_noport++;
206118611Snjl			return;
207118611Snjl		}
208118611Snjl		break;
209118611Snjl	case ICMP6_PACKET_TOO_BIG:
210118611Snjl		stat->icp6errs_packet_too_big++;
211118611Snjl		return;
212118611Snjl	case ICMP6_TIME_EXCEEDED:
213151937Sjkim		switch (code) {
214118611Snjl		case ICMP6_TIME_EXCEED_TRANSIT:
215118611Snjl			stat->icp6errs_time_exceed_transit++;
216118611Snjl			return;
217118611Snjl		case ICMP6_TIME_EXCEED_REASSEMBLY:
218118611Snjl			stat->icp6errs_time_exceed_reassembly++;
219118611Snjl			return;
220118611Snjl		}
221118611Snjl		break;
222118611Snjl	case ICMP6_PARAM_PROB:
223118611Snjl		switch (code) {
224118611Snjl		case ICMP6_PARAMPROB_HEADER:
225118611Snjl			stat->icp6errs_paramprob_header++;
226118611Snjl			return;
227118611Snjl		case ICMP6_PARAMPROB_NEXTHEADER:
228118611Snjl			stat->icp6errs_paramprob_nextheader++;
229118611Snjl			return;
230118611Snjl		case ICMP6_PARAMPROB_OPTION:
231118611Snjl			stat->icp6errs_paramprob_option++;
232118611Snjl			return;
233118611Snjl		}
234118611Snjl		break;
235151937Sjkim	case ND_REDIRECT:
236151937Sjkim		stat->icp6errs_redirect++;
237118611Snjl		return;
238118611Snjl	}
239118611Snjl	stat->icp6errs_unknown++;
240118611Snjl}
241118611Snjl
242118611Snjl/*
243118611Snjl * Generate an error packet of type error in response to bad IP6 packet.
244118611Snjl */
245118611Snjlvoid
246193529Sjkimicmp6_error(m, type, code, param)
247193529Sjkim	struct mbuf *m;
248193529Sjkim	int type, code, param;
249193529Sjkim{
250193529Sjkim	struct ip6_hdr *oip6, *nip6;
251151937Sjkim	struct icmp6_hdr *icmp6;
252151937Sjkim	u_int preplen;
253151937Sjkim	int off;
254151937Sjkim	int nxt;
255118611Snjl
256118611Snjl	icmp6stat.icp6s_error++;
257118611Snjl
258118611Snjl	/* count per-type-code statistics */
259118611Snjl	icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
260118611Snjl
261118611Snjl#ifdef M_DECRYPTED	/*not openbsd*/
262118611Snjl	if (m->m_flags & M_DECRYPTED) {
263118611Snjl		icmp6stat.icp6s_canterror++;
264118611Snjl		goto freeit;
265118611Snjl	}
266118611Snjl#endif
267118611Snjl
268118611Snjl#ifndef PULLDOWN_TEST
269118611Snjl	IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
270118611Snjl#else
271118611Snjl	if (m->m_len < sizeof(struct ip6_hdr)) {
272118611Snjl		m = m_pullup(m, sizeof(struct ip6_hdr));
273118611Snjl		if (m == NULL)
274118611Snjl			return;
275118611Snjl	}
276118611Snjl#endif
277118611Snjl	oip6 = mtod(m, struct ip6_hdr *);
278118611Snjl
279118611Snjl	/*
280118611Snjl	 * Multicast destination check. For unrecognized option errors,
281118611Snjl	 * this check has already done in ip6_unknown_opt(), so we can
282118611Snjl	 * check only for other errors.
283118611Snjl	 */
284118611Snjl	if ((m->m_flags & (M_BCAST|M_MCAST) ||
285118611Snjl	     IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
286118611Snjl	    (type != ICMP6_PACKET_TOO_BIG &&
287118611Snjl	     (type != ICMP6_PARAM_PROB ||
288118611Snjl	      code != ICMP6_PARAMPROB_OPTION)))
289118611Snjl		goto freeit;
290118611Snjl
291118611Snjl	/* Source address check. XXX: the case of anycast source? */
292118611Snjl	if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
293118611Snjl	    IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
294118611Snjl		goto freeit;
295118611Snjl
296118611Snjl	/*
297118611Snjl	 * If we are about to send ICMPv6 against ICMPv6 error/redirect,
298118611Snjl	 * don't do it.
299118611Snjl	 */
300118611Snjl	nxt = -1;
301118611Snjl	off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
302118611Snjl	if (off >= 0 && nxt == IPPROTO_ICMPV6) {
303118611Snjl		struct icmp6_hdr *icp;
304118611Snjl
305118611Snjl#ifndef PULLDOWN_TEST
306151937Sjkim		IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
307151937Sjkim		icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
308118611Snjl#else
309118611Snjl		IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
310151937Sjkim			sizeof(*icp));
311193529Sjkim		if (icp == NULL) {
312193529Sjkim			icmp6stat.icp6s_tooshort++;
313118611Snjl			return;
314118611Snjl		}
315118611Snjl#endif
316151937Sjkim		if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
317151937Sjkim		    icp->icmp6_type == ND_REDIRECT) {
318118611Snjl			/*
319151937Sjkim			 * ICMPv6 error
320193529Sjkim			 * Special case: for redirect (which is
321193529Sjkim			 * informational) we must not send icmp6 error.
322118611Snjl			 */
323118611Snjl			icmp6stat.icp6s_canterror++;
324151937Sjkim			goto freeit;
325118611Snjl		} else {
326118611Snjl			/* ICMPv6 informational - send the error */
327151937Sjkim		}
328118611Snjl	} else {
329118611Snjl		/* non-ICMPv6 - send the error */
330118611Snjl	}
331118611Snjl
332118611Snjl	oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
333118611Snjl
334118611Snjl	/* Finally, do rate limitation check. */
335118611Snjl	if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
336118611Snjl		icmp6stat.icp6s_toofreq++;
337118611Snjl		goto freeit;
338118611Snjl	}
339118611Snjl
340118611Snjl	/*
341118611Snjl	 * OK, ICMP6 can be generated.
342118611Snjl	 */
343118611Snjl
344118611Snjl	if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
345118611Snjl		m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
346118611Snjl
347118611Snjl	preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
348118611Snjl	M_PREPEND(m, preplen, M_DONTWAIT);
349118611Snjl	if (m && m->m_len < preplen)
350118611Snjl		m = m_pullup(m, preplen);
351118611Snjl	if (m == NULL) {
352118611Snjl		nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
353118611Snjl		return;
354118611Snjl	}
355118611Snjl
356118611Snjl	nip6 = mtod(m, struct ip6_hdr *);
357118611Snjl	nip6->ip6_src  = oip6->ip6_src;
358118611Snjl	nip6->ip6_dst  = oip6->ip6_dst;
359118611Snjl
360118611Snjl	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
361118611Snjl		oip6->ip6_src.s6_addr16[1] = 0;
362118611Snjl	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
363118611Snjl		oip6->ip6_dst.s6_addr16[1] = 0;
364118611Snjl
365118611Snjl	icmp6 = (struct icmp6_hdr *)(nip6 + 1);
366118611Snjl	icmp6->icmp6_type = type;
367118611Snjl	icmp6->icmp6_code = code;
368118611Snjl	icmp6->icmp6_pptr = htonl((u_int32_t)param);
369118611Snjl
370118611Snjl	/*
371118611Snjl	 * icmp6_reflect() is designed to be in the input path.
372118611Snjl	 * icmp6_error() can be called from both input and outut path,
373118611Snjl	 * and if we are in output path rcvif could contain bogus value.
374118611Snjl	 * clear m->m_pkthdr.rcvif for safety, we should have enough scope
375118611Snjl	 * information in ip header (nip6).
376118611Snjl	 */
377118611Snjl	m->m_pkthdr.rcvif = NULL;
378118611Snjl
379118611Snjl	icmp6stat.icp6s_outhist[type]++;
380118611Snjl	icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
381118611Snjl
382118611Snjl	return;
383118611Snjl
384118611Snjl  freeit:
385118611Snjl	/*
386118611Snjl	 * If we can't tell wheter or not we can generate ICMP6, free it.
387118611Snjl	 */
388118611Snjl	m_freem(m);
389118611Snjl}
390118611Snjl
391118611Snjl/*
392118611Snjl * Process a received ICMP6 message.
393118611Snjl */
394118611Snjlint
395118611Snjlicmp6_input(mp, offp, proto)
396118611Snjl	struct mbuf **mp;
397118611Snjl	int *offp, proto;
398118611Snjl{
399118611Snjl	struct mbuf *m = *mp, *n;
400118611Snjl	struct ip6_hdr *ip6, *nip6;
401118611Snjl	struct icmp6_hdr *icmp6, *nicmp6;
402118611Snjl	int off = *offp;
403118611Snjl	int icmp6len = m->m_pkthdr.len - *offp;
404118611Snjl	int code, sum, noff;
405118611Snjl
406118611Snjl#ifndef PULLDOWN_TEST
407118611Snjl	IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
408118611Snjl	/* m might change if M_LOOP.  So, call mtod after this */
409118611Snjl#endif
410151937Sjkim
411118611Snjl	/*
412118611Snjl	 * Locate icmp6 structure in mbuf, and check
413118611Snjl	 * that not corrupted and of at least minimum length
414118611Snjl	 */
415118611Snjl
416118611Snjl	ip6 = mtod(m, struct ip6_hdr *);
417118611Snjl	if (icmp6len < sizeof(struct icmp6_hdr)) {
418118611Snjl		icmp6stat.icp6s_tooshort++;
419118611Snjl		goto freeit;
420118611Snjl	}
421118611Snjl
422118611Snjl	/*
423118611Snjl	 * calculate the checksum
424118611Snjl	 */
425118611Snjl#ifndef PULLDOWN_TEST
426118611Snjl	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
427118611Snjl#else
428118611Snjl	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
429118611Snjl	if (icmp6 == NULL) {
430118611Snjl		icmp6stat.icp6s_tooshort++;
431118611Snjl		return IPPROTO_DONE;
432118611Snjl	}
433118611Snjl#endif
434118611Snjl	code = icmp6->icmp6_code;
435118611Snjl
436118611Snjl	if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
437118611Snjl		nd6log((LOG_ERR,
438118611Snjl		    "ICMP6 checksum error(%d|%x) %s\n",
439118611Snjl		    icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src)));
440118611Snjl		icmp6stat.icp6s_checksum++;
441118611Snjl		goto freeit;
442118611Snjl	}
443118611Snjl
444118611Snjl	if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
445118611Snjl		/*
446118611Snjl		 * Deliver very specific ICMP6 type only.
447118611Snjl		 * This is important to deilver TOOBIG.  Otherwise PMTUD
448118611Snjl		 * will not work.
449118611Snjl		 */
450118611Snjl		switch (icmp6->icmp6_type) {
451118611Snjl		case ICMP6_DST_UNREACH:
452118611Snjl		case ICMP6_PACKET_TOO_BIG:
453118611Snjl		case ICMP6_TIME_EXCEEDED:
454118611Snjl			break;
455118611Snjl		default:
456118611Snjl			goto freeit;
457118611Snjl		}
458151937Sjkim	}
459118611Snjl
460118611Snjl	icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
461118611Snjl	icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
462118611Snjl	if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
463118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
464118611Snjl
465118611Snjl	switch (icmp6->icmp6_type) {
466118611Snjl	case ICMP6_DST_UNREACH:
467118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
468118611Snjl		switch (code) {
469118611Snjl		case ICMP6_DST_UNREACH_NOROUTE:
470118611Snjl			code = PRC_UNREACH_NET;
471118611Snjl			break;
472118611Snjl		case ICMP6_DST_UNREACH_ADMIN:
473118611Snjl			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
474118611Snjl			code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
475118611Snjl			break;
476118611Snjl		case ICMP6_DST_UNREACH_ADDR:
477118611Snjl			code = PRC_HOSTDEAD;
478118611Snjl			break;
479118611Snjl#ifdef COMPAT_RFC1885
480118611Snjl		case ICMP6_DST_UNREACH_NOTNEIGHBOR:
481118611Snjl			code = PRC_UNREACH_SRCFAIL;
482118611Snjl			break;
483118611Snjl#else
484118611Snjl		case ICMP6_DST_UNREACH_BEYONDSCOPE:
485118611Snjl			/* I mean "source address was incorrect." */
486118611Snjl			code = PRC_PARAMPROB;
487118611Snjl			break;
488118611Snjl#endif
489118611Snjl		case ICMP6_DST_UNREACH_NOPORT:
490118611Snjl			code = PRC_UNREACH_PORT;
491118611Snjl			break;
492118611Snjl		default:
493118611Snjl			goto badcode;
494118611Snjl		}
495118611Snjl		goto deliver;
496118611Snjl		break;
497118611Snjl
498118611Snjl	case ICMP6_PACKET_TOO_BIG:
499118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
500118611Snjl		if (code != 0)
501118611Snjl			goto badcode;
502118611Snjl
503118611Snjl		code = PRC_MSGSIZE;
504118611Snjl
505118611Snjl		/*
506118611Snjl		 * Updating the path MTU will be done after examining
507118611Snjl		 * intermediate extension headers.
508118611Snjl		 */
509118611Snjl		goto deliver;
510118611Snjl		break;
511118611Snjl
512118611Snjl	case ICMP6_TIME_EXCEEDED:
513118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
514118611Snjl		switch (code) {
515118611Snjl		case ICMP6_TIME_EXCEED_TRANSIT:
516118611Snjl		case ICMP6_TIME_EXCEED_REASSEMBLY:
517118611Snjl			code += PRC_TIMXCEED_INTRANS;
518118611Snjl			break;
519118611Snjl		default:
520118611Snjl			goto badcode;
521118611Snjl		}
522118611Snjl		goto deliver;
523118611Snjl		break;
524118611Snjl
525118611Snjl	case ICMP6_PARAM_PROB:
526118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
527118611Snjl		switch (code) {
528167802Sjkim		case ICMP6_PARAMPROB_NEXTHEADER:
529118611Snjl			code = PRC_UNREACH_PROTOCOL;
530118611Snjl			break;
531118611Snjl		case ICMP6_PARAMPROB_HEADER:
532118611Snjl		case ICMP6_PARAMPROB_OPTION:
533118611Snjl			code = PRC_PARAMPROB;
534199337Sjkim			break;
535118611Snjl		default:
536118611Snjl			goto badcode;
537118611Snjl		}
538118611Snjl		goto deliver;
539118611Snjl		break;
540118611Snjl
541118611Snjl	case ICMP6_ECHO_REQUEST:
542118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
543118611Snjl		if (code != 0)
544118611Snjl			goto badcode;
545118611Snjl		if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
546118611Snjl			/* Give up remote */
547118611Snjl			break;
548118611Snjl		}
549118611Snjl		if ((n->m_flags & M_EXT) != 0
550118611Snjl		 || n->m_len < off + sizeof(struct icmp6_hdr)) {
551118611Snjl			struct mbuf *n0 = n;
552118611Snjl			const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
553118611Snjl
554118611Snjl			/*
555118611Snjl			 * Prepare an internal mbuf. m_pullup() doesn't
556118611Snjl			 * always copy the length we specified.
557118611Snjl			 */
558118611Snjl			if (maxlen >= MCLBYTES) {
559118611Snjl				/* Give up remote */
560118611Snjl				m_freem(n0);
561118611Snjl				break;
562118611Snjl			}
563118611Snjl			MGETHDR(n, M_DONTWAIT, n0->m_type);
564118611Snjl			if (n && maxlen >= MHLEN) {
565167802Sjkim				MCLGET(n, M_DONTWAIT);
566167802Sjkim				if ((n->m_flags & M_EXT) == 0) {
567167802Sjkim					m_free(n);
568167802Sjkim					n = NULL;
569167802Sjkim				}
570167802Sjkim			}
571167802Sjkim			if (n == NULL) {
572167802Sjkim				/* Give up remote */
573167802Sjkim				m_freem(n0);
574167802Sjkim				break;
575167802Sjkim			}
576167802Sjkim			M_COPY_PKTHDR(n, n0);
577167802Sjkim			/*
578167802Sjkim			 * Copy IPv6 and ICMPv6 only.
579167802Sjkim			 */
580118611Snjl			nip6 = mtod(n, struct ip6_hdr *);
581118611Snjl			bcopy(ip6, nip6, sizeof(struct ip6_hdr));
582118611Snjl			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
583118611Snjl			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
584118611Snjl			noff = sizeof(struct ip6_hdr);
585118611Snjl			n->m_pkthdr.len = n->m_len =
586118611Snjl				noff + sizeof(struct icmp6_hdr);
587118611Snjl			/*
588118611Snjl			 * Adjust mbuf. ip6_plen will be adjusted in
589118611Snjl			 * ip6_output().
590118611Snjl			 */
591118611Snjl			m_adj(n0, off + sizeof(struct icmp6_hdr));
592118611Snjl			n->m_pkthdr.len += n0->m_pkthdr.len;
593118611Snjl			n->m_next = n0;
594118611Snjl			n0->m_flags &= ~M_PKTHDR;
595118611Snjl		} else {
596118611Snjl			nip6 = mtod(n, struct ip6_hdr *);
597118611Snjl			nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off);
598118611Snjl			noff = off;
599118611Snjl		}
600118611Snjl		nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
601118611Snjl		nicmp6->icmp6_code = 0;
602118611Snjl		if (n) {
603118611Snjl			icmp6stat.icp6s_reflect++;
604118611Snjl			icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
605118611Snjl			icmp6_reflect(n, noff);
606118611Snjl		}
607118611Snjl		break;
608118611Snjl
609118611Snjl	case ICMP6_ECHO_REPLY:
610118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
611118611Snjl		if (code != 0)
612118611Snjl			goto badcode;
613118611Snjl		break;
614118611Snjl
615118611Snjl	case MLD_LISTENER_QUERY:
616118611Snjl	case MLD_LISTENER_REPORT:
617118611Snjl		if (icmp6len < sizeof(struct mld_hdr))
618118611Snjl			goto badlen;
619118611Snjl		if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */
620118611Snjl			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
621118611Snjl		else
622118611Snjl			icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
623118611Snjl		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
624118611Snjl			/* give up local */
625118611Snjl			mld6_input(m, off);
626118611Snjl			m = NULL;
627118611Snjl			goto freeit;
628118611Snjl		}
629118611Snjl		mld6_input(n, off);
630118611Snjl		/* m stays. */
631118611Snjl		break;
632118611Snjl
633118611Snjl	case MLD_LISTENER_DONE:
634118611Snjl		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
635118611Snjl		if (icmp6len < sizeof(struct mld_hdr))	/* necessary? */
636118611Snjl			goto badlen;
637118611Snjl		break;		/* nothing to be done in kernel */
638118611Snjl
639118611Snjl	case MLD_MTRACE_RESP:
640118611Snjl	case MLD_MTRACE:
641118611Snjl		/* XXX: these two are experimental.  not officially defind. */
642118611Snjl		/* XXX: per-interface statistics? */
643118611Snjl		break;		/* just pass it to applications */
644118611Snjl
645118611Snjl	case ICMP6_WRUREQUEST:	/* ICMP6_FQDN_QUERY */
646118611Snjl	    {
647118611Snjl		enum { WRU, FQDN } mode;
648118611Snjl
649151937Sjkim		if (!icmp6_nodeinfo)
650118611Snjl			break;
651118611Snjl
652151937Sjkim		if (icmp6len == sizeof(struct icmp6_hdr) + 4)
653151937Sjkim			mode = WRU;
654118611Snjl		else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
655118611Snjl			mode = FQDN;
656118611Snjl		else
657118611Snjl			goto badlen;
658118611Snjl
659118611Snjl#define hostnamelen	strlen(hostname)
660118611Snjl		if (mode == FQDN) {
661118611Snjl#ifndef PULLDOWN_TEST
662118611Snjl			IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
663118611Snjl					 IPPROTO_DONE);
664118611Snjl#endif
665118611Snjl			n = m_copy(m, 0, M_COPYALL);
666118611Snjl			if (n)
667118611Snjl				n = ni6_input(n, off);
668118611Snjl			/* XXX meaningless if n == NULL */
669118611Snjl			noff = sizeof(struct ip6_hdr);
670118611Snjl		} else {
671			u_char *p;
672			int maxlen, maxhlen;
673
674			if ((icmp6_nodeinfo & 5) != 5)
675				break;
676
677			if (code != 0)
678				goto badcode;
679			maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
680			if (maxlen >= MCLBYTES) {
681				/* Give up remote */
682				break;
683			}
684			MGETHDR(n, M_DONTWAIT, m->m_type);
685			if (n && maxlen > MHLEN) {
686				MCLGET(n, M_DONTWAIT);
687				if ((n->m_flags & M_EXT) == 0) {
688					m_free(n);
689					n = NULL;
690				}
691			}
692			if (n == NULL) {
693				/* Give up remote */
694				break;
695			}
696			n->m_pkthdr.rcvif = NULL;
697			n->m_len = 0;
698			maxhlen = M_TRAILINGSPACE(n) - maxlen;
699			if (maxhlen > hostnamelen)
700				maxhlen = hostnamelen;
701			/*
702			 * Copy IPv6 and ICMPv6 only.
703			 */
704			nip6 = mtod(n, struct ip6_hdr *);
705			bcopy(ip6, nip6, sizeof(struct ip6_hdr));
706			nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
707			bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
708			p = (u_char *)(nicmp6 + 1);
709			bzero(p, 4);
710			bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */
711			noff = sizeof(struct ip6_hdr);
712			M_COPY_PKTHDR(n, m); /* just for rcvif */
713			n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
714				sizeof(struct icmp6_hdr) + 4 + maxhlen;
715			nicmp6->icmp6_type = ICMP6_WRUREPLY;
716			nicmp6->icmp6_code = 0;
717		}
718#undef hostnamelen
719		if (n) {
720			icmp6stat.icp6s_reflect++;
721			icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
722			icmp6_reflect(n, noff);
723		}
724		break;
725	    }
726
727	case ICMP6_WRUREPLY:
728		if (code != 0)
729			goto badcode;
730		break;
731
732	case ND_ROUTER_SOLICIT:
733		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
734		if (code != 0)
735			goto badcode;
736		if (icmp6len < sizeof(struct nd_router_solicit))
737			goto badlen;
738		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
739			/* give up local */
740			nd6_rs_input(m, off, icmp6len);
741			m = NULL;
742			goto freeit;
743		}
744		nd6_rs_input(n, off, icmp6len);
745		/* m stays. */
746		break;
747
748	case ND_ROUTER_ADVERT:
749		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
750		if (code != 0)
751			goto badcode;
752		if (icmp6len < sizeof(struct nd_router_advert))
753			goto badlen;
754		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
755			/* give up local */
756			nd6_ra_input(m, off, icmp6len);
757			m = NULL;
758			goto freeit;
759		}
760		nd6_ra_input(n, off, icmp6len);
761		/* m stays. */
762		break;
763
764	case ND_NEIGHBOR_SOLICIT:
765		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
766		if (code != 0)
767			goto badcode;
768		if (icmp6len < sizeof(struct nd_neighbor_solicit))
769			goto badlen;
770		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
771			/* give up local */
772			nd6_ns_input(m, off, icmp6len);
773			m = NULL;
774			goto freeit;
775		}
776		nd6_ns_input(n, off, icmp6len);
777		/* m stays. */
778		break;
779
780	case ND_NEIGHBOR_ADVERT:
781		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
782		if (code != 0)
783			goto badcode;
784		if (icmp6len < sizeof(struct nd_neighbor_advert))
785			goto badlen;
786		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
787			/* give up local */
788			nd6_na_input(m, off, icmp6len);
789			m = NULL;
790			goto freeit;
791		}
792		nd6_na_input(n, off, icmp6len);
793		/* m stays. */
794		break;
795
796	case ND_REDIRECT:
797		icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
798		if (code != 0)
799			goto badcode;
800		if (icmp6len < sizeof(struct nd_redirect))
801			goto badlen;
802		if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
803			/* give up local */
804			icmp6_redirect_input(m, off);
805			m = NULL;
806			goto freeit;
807		}
808		icmp6_redirect_input(n, off);
809		/* m stays. */
810		break;
811
812	case ICMP6_ROUTER_RENUMBERING:
813		if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
814		    code != ICMP6_ROUTER_RENUMBERING_RESULT)
815			goto badcode;
816		if (icmp6len < sizeof(struct icmp6_router_renum))
817			goto badlen;
818		break;
819
820	default:
821		nd6log((LOG_DEBUG,
822		    "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
823		    icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
824		    ip6_sprintf(&ip6->ip6_dst),
825		    m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
826		if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
827			/* ICMPv6 error: MUST deliver it by spec... */
828			code = PRC_NCMDS;
829			/* deliver */
830		} else {
831			/* ICMPv6 informational: MUST not deliver */
832			break;
833		}
834	deliver:
835		if (icmp6_notify_error(m, off, icmp6len, code)) {
836			/* In this case, m should've been freed. */
837			return(IPPROTO_DONE);
838		}
839		break;
840
841	badcode:
842		icmp6stat.icp6s_badcode++;
843		break;
844
845	badlen:
846		icmp6stat.icp6s_badlen++;
847		break;
848	}
849
850	/* deliver the packet to appropriate sockets */
851	icmp6_rip6_input(&m, *offp);
852
853	return IPPROTO_DONE;
854
855 freeit:
856	m_freem(m);
857	return IPPROTO_DONE;
858}
859
860static int
861icmp6_notify_error(m, off, icmp6len, code)
862	struct mbuf *m;
863	int off, icmp6len;
864{
865	struct icmp6_hdr *icmp6;
866	struct ip6_hdr *eip6;
867	u_int32_t notifymtu;
868	struct sockaddr_in6 icmp6src, icmp6dst;
869
870	if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
871		icmp6stat.icp6s_tooshort++;
872		goto freeit;
873	}
874#ifndef PULLDOWN_TEST
875	IP6_EXTHDR_CHECK(m, off,
876			 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
877			 -1);
878	icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
879#else
880	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
881		       sizeof(*icmp6) + sizeof(struct ip6_hdr));
882	if (icmp6 == NULL) {
883		icmp6stat.icp6s_tooshort++;
884		return(-1);
885	}
886#endif
887	eip6 = (struct ip6_hdr *)(icmp6 + 1);
888
889	/* Detect the upper level protocol */
890	{
891		void (*ctlfunc) __P((int, struct sockaddr *, void *));
892		u_int8_t nxt = eip6->ip6_nxt;
893		int eoff = off + sizeof(struct icmp6_hdr) +
894			sizeof(struct ip6_hdr);
895		struct ip6ctlparam ip6cp;
896		struct in6_addr *finaldst = NULL;
897		int icmp6type = icmp6->icmp6_type;
898		struct ip6_frag *fh;
899		struct ip6_rthdr *rth;
900		struct ip6_rthdr0 *rth0;
901		int rthlen;
902
903		while (1) { /* XXX: should avoid infinite loop explicitly? */
904			struct ip6_ext *eh;
905
906			switch (nxt) {
907			case IPPROTO_HOPOPTS:
908			case IPPROTO_DSTOPTS:
909			case IPPROTO_AH:
910#ifndef PULLDOWN_TEST
911				IP6_EXTHDR_CHECK(m, 0, eoff +
912						 sizeof(struct ip6_ext),
913						 -1);
914				eh = (struct ip6_ext *)(mtod(m, caddr_t)
915							+ eoff);
916#else
917				IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
918					       eoff, sizeof(*eh));
919				if (eh == NULL) {
920					icmp6stat.icp6s_tooshort++;
921					return(-1);
922				}
923#endif
924
925				if (nxt == IPPROTO_AH)
926					eoff += (eh->ip6e_len + 2) << 2;
927				else
928					eoff += (eh->ip6e_len + 1) << 3;
929				nxt = eh->ip6e_nxt;
930				break;
931			case IPPROTO_ROUTING:
932				/*
933				 * When the erroneous packet contains a
934				 * routing header, we should examine the
935				 * header to determine the final destination.
936				 * Otherwise, we can't properly update
937				 * information that depends on the final
938				 * destination (e.g. path MTU).
939				 */
940#ifndef PULLDOWN_TEST
941				IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
942						 -1);
943				rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
944							   + eoff);
945#else
946				IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
947					       eoff, sizeof(*rth));
948				if (rth == NULL) {
949					icmp6stat.icp6s_tooshort++;
950					return(-1);
951				}
952#endif
953				rthlen = (rth->ip6r_len + 1) << 3;
954				/*
955				 * XXX: currently there is no
956				 * officially defined type other
957				 * than type-0.
958				 * Note that if the segment left field
959				 * is 0, all intermediate hops must
960				 * have been passed.
961				 */
962				if (rth->ip6r_segleft &&
963				    rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
964					int hops;
965
966#ifndef PULLDOWN_TEST
967					IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
968							 -1);
969					rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
970#else
971					IP6_EXTHDR_GET(rth0,
972						       struct ip6_rthdr0 *, m,
973						       eoff, rthlen);
974					if (rth0 == NULL) {
975						icmp6stat.icp6s_tooshort++;
976						return(-1);
977					}
978#endif
979					/* just ignore a bogus header */
980					if ((rth0->ip6r0_len % 2) == 0 &&
981					    (hops = rth0->ip6r0_len/2))
982						finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
983				}
984				eoff += rthlen;
985				nxt = rth->ip6r_nxt;
986				break;
987			case IPPROTO_FRAGMENT:
988#ifndef PULLDOWN_TEST
989				IP6_EXTHDR_CHECK(m, 0, eoff +
990						 sizeof(struct ip6_frag),
991						 -1);
992				fh = (struct ip6_frag *)(mtod(m, caddr_t)
993							 + eoff);
994#else
995				IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
996					       eoff, sizeof(*fh));
997				if (fh == NULL) {
998					icmp6stat.icp6s_tooshort++;
999					return(-1);
1000				}
1001#endif
1002				/*
1003				 * Data after a fragment header is meaningless
1004				 * unless it is the first fragment, but
1005				 * we'll go to the notify label for path MTU
1006				 * discovery.
1007				 */
1008				if (fh->ip6f_offlg & IP6F_OFF_MASK)
1009					goto notify;
1010
1011				eoff += sizeof(struct ip6_frag);
1012				nxt = fh->ip6f_nxt;
1013				break;
1014			default:
1015				/*
1016				 * This case includes ESP and the No Next
1017				 * Header.  In such cases going to the notify
1018				 * label does not have any meaning
1019				 * (i.e. ctlfunc will be NULL), but we go
1020				 * anyway since we might have to update
1021				 * path MTU information.
1022				 */
1023				goto notify;
1024			}
1025		}
1026	  notify:
1027#ifndef PULLDOWN_TEST
1028		icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
1029#else
1030		IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
1031			       sizeof(*icmp6) + sizeof(struct ip6_hdr));
1032		if (icmp6 == NULL) {
1033			icmp6stat.icp6s_tooshort++;
1034			return(-1);
1035		}
1036#endif
1037
1038		eip6 = (struct ip6_hdr *)(icmp6 + 1);
1039		bzero(&icmp6dst, sizeof(icmp6dst));
1040		icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
1041		icmp6dst.sin6_family = AF_INET6;
1042		if (finaldst == NULL)
1043			icmp6dst.sin6_addr = eip6->ip6_dst;
1044		else
1045			icmp6dst.sin6_addr = *finaldst;
1046		icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1047							  &icmp6dst.sin6_addr);
1048#ifndef SCOPEDROUTING
1049		if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
1050				   NULL, NULL)) {
1051			/* should be impossbile */
1052			nd6log((LOG_DEBUG,
1053			    "icmp6_notify_error: in6_embedscope failed\n"));
1054			goto freeit;
1055		}
1056#endif
1057
1058		/*
1059		 * retrieve parameters from the inner IPv6 header, and convert
1060		 * them into sockaddr structures.
1061		 */
1062		bzero(&icmp6src, sizeof(icmp6src));
1063		icmp6src.sin6_len = sizeof(struct sockaddr_in6);
1064		icmp6src.sin6_family = AF_INET6;
1065		icmp6src.sin6_addr = eip6->ip6_src;
1066		icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1067							  &icmp6src.sin6_addr);
1068#ifndef SCOPEDROUTING
1069		if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
1070				   NULL, NULL)) {
1071			/* should be impossbile */
1072			nd6log((LOG_DEBUG,
1073			    "icmp6_notify_error: in6_embedscope failed\n"));
1074			goto freeit;
1075		}
1076#endif
1077		icmp6src.sin6_flowinfo =
1078			(eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
1079
1080		if (finaldst == NULL)
1081			finaldst = &eip6->ip6_dst;
1082		ip6cp.ip6c_m = m;
1083		ip6cp.ip6c_icmp6 = icmp6;
1084		ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
1085		ip6cp.ip6c_off = eoff;
1086		ip6cp.ip6c_finaldst = finaldst;
1087		ip6cp.ip6c_src = &icmp6src;
1088		ip6cp.ip6c_nxt = nxt;
1089
1090		if (icmp6type == ICMP6_PACKET_TOO_BIG) {
1091			notifymtu = ntohl(icmp6->icmp6_mtu);
1092			ip6cp.ip6c_cmdarg = (void *)&notifymtu;
1093			icmp6_mtudisc_update(&ip6cp, 1);	/*XXX*/
1094		}
1095
1096		ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
1097			(inet6sw[ip6_protox[nxt]].pr_ctlinput);
1098		if (ctlfunc) {
1099			(void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
1100					  &ip6cp);
1101		}
1102	}
1103	return(0);
1104
1105  freeit:
1106	m_freem(m);
1107	return(-1);
1108}
1109
1110void
1111icmp6_mtudisc_update(ip6cp, validated)
1112	struct ip6ctlparam *ip6cp;
1113	int validated;
1114{
1115	struct in6_addr *dst = ip6cp->ip6c_finaldst;
1116	struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
1117	struct mbuf *m = ip6cp->ip6c_m;	/* will be necessary for scope issue */
1118	u_int mtu = ntohl(icmp6->icmp6_mtu);
1119	struct rtentry *rt = NULL;
1120	struct sockaddr_in6 sin6;
1121
1122	if (!validated)
1123		return;
1124
1125	bzero(&sin6, sizeof(sin6));
1126	sin6.sin6_family = PF_INET6;
1127	sin6.sin6_len = sizeof(struct sockaddr_in6);
1128	sin6.sin6_addr = *dst;
1129	/* XXX normally, this won't happen */
1130	if (IN6_IS_ADDR_LINKLOCAL(dst)) {
1131		sin6.sin6_addr.s6_addr16[1] =
1132		    htons(m->m_pkthdr.rcvif->if_index);
1133	}
1134	/* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
1135	rt = rtalloc1((struct sockaddr *)&sin6, 0,
1136		      RTF_CLONING | RTF_PRCLONING);
1137
1138	if (rt && (rt->rt_flags & RTF_HOST)
1139	    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
1140		if (mtu < IPV6_MMTU) {
1141				/* xxx */
1142			rt->rt_rmx.rmx_locks |= RTV_MTU;
1143		} else if (mtu < rt->rt_ifp->if_mtu &&
1144			   rt->rt_rmx.rmx_mtu > mtu) {
1145			icmp6stat.icp6s_pmtuchg++;
1146			rt->rt_rmx.rmx_mtu = mtu;
1147		}
1148	}
1149	if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */
1150		RTFREE(rt);
1151	}
1152}
1153
1154/*
1155 * Process a Node Information Query packet, based on
1156 * draft-ietf-ipngwg-icmp-name-lookups-07.
1157 *
1158 * Spec incompatibilities:
1159 * - IPv6 Subject address handling
1160 * - IPv4 Subject address handling support missing
1161 * - Proxy reply (answer even if it's not for me)
1162 * - joins NI group address at in6_ifattach() time only, does not cope
1163 *   with hostname changes by sethostname(3)
1164 */
1165#define hostnamelen	strlen(hostname)
1166static struct mbuf *
1167ni6_input(m, off)
1168	struct mbuf *m;
1169	int off;
1170{
1171	struct icmp6_nodeinfo *ni6, *nni6;
1172	struct mbuf *n = NULL;
1173	u_int16_t qtype;
1174	int subjlen;
1175	int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1176	struct ni_reply_fqdn *fqdn;
1177	int addrs;		/* for NI_QTYPE_NODEADDR */
1178	struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
1179	struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */
1180	struct sockaddr_in6 sin6_d; /* XXX: we should retrieve this from m_aux */
1181	struct ip6_hdr *ip6;
1182	int oldfqdn = 0;	/* if 1, return pascal string (03 draft) */
1183	char *subj = NULL;
1184	struct in6_ifaddr *ia6 = NULL;
1185
1186	ip6 = mtod(m, struct ip6_hdr *);
1187#ifndef PULLDOWN_TEST
1188	ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
1189#else
1190	IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
1191	if (ni6 == NULL) {
1192		/* m is already reclaimed */
1193		return NULL;
1194	}
1195#endif
1196
1197	/*
1198	 * Validate IPv6 destination address.
1199	 *
1200	 * The Responder must discard the Query without further processing
1201	 * unless it is one of the Responder's unicast or anycast addresses, or
1202	 * a link-local scope multicast address which the Responder has joined.
1203	 * [icmp-name-lookups-07, Section 4.]
1204	 */
1205	bzero(&sin6, sizeof(sin6));
1206	sin6.sin6_family = AF_INET6;
1207	sin6.sin6_len = sizeof(struct sockaddr_in6);
1208	bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
1209	/* XXX scopeid */
1210	if ((ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)&sin6)) != NULL) {
1211		/* unicast/anycast, fine */
1212		if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
1213		    (icmp6_nodeinfo & 4) == 0) {
1214			nd6log((LOG_DEBUG, "ni6_input: ignore node info to "
1215				"a temporary address in %s:%d",
1216			       __FILE__, __LINE__));
1217			goto bad;
1218		}
1219	} else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
1220		; /* link-local multicast, fine */
1221	else
1222		goto bad;
1223
1224	/* validate query Subject field. */
1225	qtype = ntohs(ni6->ni_qtype);
1226	subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
1227	switch (qtype) {
1228	case NI_QTYPE_NOOP:
1229	case NI_QTYPE_SUPTYPES:
1230		/* 07 draft */
1231		if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)
1232			break;
1233		/* FALLTHROUGH */
1234	case NI_QTYPE_FQDN:
1235	case NI_QTYPE_NODEADDR:
1236		switch (ni6->ni_code) {
1237		case ICMP6_NI_SUBJ_IPV6:
1238#if ICMP6_NI_SUBJ_IPV6 != 0
1239		case 0:
1240#endif
1241			/*
1242			 * backward compatibility - try to accept 03 draft
1243			 * format, where no Subject is present.
1244			 */
1245			if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
1246			    subjlen == 0) {
1247				oldfqdn++;
1248				break;
1249			}
1250#if ICMP6_NI_SUBJ_IPV6 != 0
1251			if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)
1252				goto bad;
1253#endif
1254
1255			if (subjlen != sizeof(sin6.sin6_addr))
1256				goto bad;
1257
1258			/*
1259			 * Validate Subject address.
1260			 *
1261			 * Not sure what exactly "address belongs to the node"
1262			 * means in the spec, is it just unicast, or what?
1263			 *
1264			 * At this moment we consider Subject address as
1265			 * "belong to the node" if the Subject address equals
1266			 * to the IPv6 destination address; validation for
1267			 * IPv6 destination address should have done enough
1268			 * check for us.
1269			 *
1270			 * We do not do proxy at this moment.
1271			 */
1272			/* m_pulldown instead of copy? */
1273			m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
1274			    subjlen, (caddr_t)&sin6.sin6_addr);
1275			sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1276							      &sin6.sin6_addr);
1277#ifndef SCOPEDROUTING
1278			in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL);
1279#endif
1280			bzero(&sin6_d, sizeof(sin6_d));
1281			sin6_d.sin6_family = AF_INET6; /* not used, actually */
1282			sin6_d.sin6_len = sizeof(sin6_d); /* ditto */
1283			sin6_d.sin6_addr = ip6->ip6_dst;
1284			sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1285								&ip6->ip6_dst);
1286#ifndef SCOPEDROUTING
1287			in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL);
1288#endif
1289			subj = (char *)&sin6;
1290			if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d))
1291				break;
1292
1293			/*
1294			 * XXX if we are to allow other cases, we should really
1295			 * be careful about scope here.
1296			 * basically, we should disallow queries toward IPv6
1297			 * destination X with subject Y, if scope(X) > scope(Y).
1298			 * if we allow scope(X) > scope(Y), it will result in
1299			 * information leakage across scope boundary.
1300			 */
1301			goto bad;
1302
1303		case ICMP6_NI_SUBJ_FQDN:
1304			/*
1305			 * Validate Subject name with gethostname(3).
1306			 *
1307			 * The behavior may need some debate, since:
1308			 * - we are not sure if the node has FQDN as
1309			 *   hostname (returned by gethostname(3)).
1310			 * - the code does wildcard match for truncated names.
1311			 *   however, we are not sure if we want to perform
1312			 *   wildcard match, if gethostname(3) side has
1313			 *   truncated hostname.
1314			 */
1315			n = ni6_nametodns(hostname, hostnamelen, 0);
1316			if (!n || n->m_next || n->m_len == 0)
1317				goto bad;
1318			IP6_EXTHDR_GET(subj, char *, m,
1319			    off + sizeof(struct icmp6_nodeinfo), subjlen);
1320			if (subj == NULL)
1321				goto bad;
1322			if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
1323					n->m_len)) {
1324				goto bad;
1325			}
1326			m_freem(n);
1327			n = NULL;
1328			break;
1329
1330		case ICMP6_NI_SUBJ_IPV4:	/* XXX: to be implemented? */
1331		default:
1332			goto bad;
1333		}
1334		break;
1335	}
1336
1337	/* refuse based on configuration.  XXX ICMP6_NI_REFUSED? */
1338	switch (qtype) {
1339	case NI_QTYPE_FQDN:
1340		if ((icmp6_nodeinfo & 1) == 0)
1341			goto bad;
1342		break;
1343	case NI_QTYPE_NODEADDR:
1344		if ((icmp6_nodeinfo & 2) == 0)
1345			goto bad;
1346		break;
1347	}
1348
1349	/* guess reply length */
1350	switch (qtype) {
1351	case NI_QTYPE_NOOP:
1352		break;		/* no reply data */
1353	case NI_QTYPE_SUPTYPES:
1354		replylen += sizeof(u_int32_t);
1355		break;
1356	case NI_QTYPE_FQDN:
1357		/* XXX will append an mbuf */
1358		replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1359		break;
1360	case NI_QTYPE_NODEADDR:
1361		addrs = ni6_addrs(ni6, m, &ifp, subj);
1362		if ((replylen += addrs * (sizeof(struct in6_addr) +
1363					  sizeof(u_int32_t))) > MCLBYTES)
1364			replylen = MCLBYTES; /* XXX: will truncate pkt later */
1365		break;
1366	default:
1367		/*
1368		 * XXX: We must return a reply with the ICMP6 code
1369		 * `unknown Qtype' in this case. However we regard the case
1370		 * as an FQDN query for backward compatibility.
1371		 * Older versions set a random value to this field,
1372		 * so it rarely varies in the defined qtypes.
1373		 * But the mechanism is not reliable...
1374		 * maybe we should obsolete older versions.
1375		 */
1376		qtype = NI_QTYPE_FQDN;
1377		/* XXX will append an mbuf */
1378		replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1379		oldfqdn++;
1380		break;
1381	}
1382
1383	/* allocate an mbuf to reply. */
1384	MGETHDR(n, M_DONTWAIT, m->m_type);
1385	if (n == NULL) {
1386		m_freem(m);
1387		return(NULL);
1388	}
1389	M_COPY_PKTHDR(n, m); /* just for recvif */
1390	if (replylen > MHLEN) {
1391		if (replylen > MCLBYTES) {
1392			/*
1393			 * XXX: should we try to allocate more? But MCLBYTES
1394			 * is probably much larger than IPV6_MMTU...
1395			 */
1396			goto bad;
1397		}
1398		MCLGET(n, M_DONTWAIT);
1399		if ((n->m_flags & M_EXT) == 0) {
1400			goto bad;
1401		}
1402	}
1403	n->m_pkthdr.len = n->m_len = replylen;
1404
1405	/* copy mbuf header and IPv6 + Node Information base headers */
1406	bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
1407	nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
1408	bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
1409
1410	/* qtype dependent procedure */
1411	switch (qtype) {
1412	case NI_QTYPE_NOOP:
1413		nni6->ni_code = ICMP6_NI_SUCCESS;
1414		nni6->ni_flags = 0;
1415		break;
1416	case NI_QTYPE_SUPTYPES:
1417	{
1418		u_int32_t v;
1419		nni6->ni_code = ICMP6_NI_SUCCESS;
1420		nni6->ni_flags = htons(0x0000);	/* raw bitmap */
1421		/* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
1422		v = (u_int32_t)htonl(0x0000000f);
1423		bcopy(&v, nni6 + 1, sizeof(u_int32_t));
1424		break;
1425	}
1426	case NI_QTYPE_FQDN:
1427		nni6->ni_code = ICMP6_NI_SUCCESS;
1428		fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
1429						sizeof(struct ip6_hdr) +
1430						sizeof(struct icmp6_nodeinfo));
1431		nni6->ni_flags = 0; /* XXX: meaningless TTL */
1432		fqdn->ni_fqdn_ttl = 0;	/* ditto. */
1433		/*
1434		 * XXX do we really have FQDN in variable "hostname"?
1435		 */
1436		n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
1437		if (n->m_next == NULL)
1438			goto bad;
1439		/* XXX we assume that n->m_next is not a chain */
1440		if (n->m_next->m_next != NULL)
1441			goto bad;
1442		n->m_pkthdr.len += n->m_next->m_len;
1443		break;
1444	case NI_QTYPE_NODEADDR:
1445	{
1446		int lenlim, copied;
1447
1448		nni6->ni_code = ICMP6_NI_SUCCESS;
1449		n->m_pkthdr.len = n->m_len =
1450		    sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1451		lenlim = M_TRAILINGSPACE(n);
1452		copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
1453		/* XXX: reset mbuf length */
1454		n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
1455			sizeof(struct icmp6_nodeinfo) + copied;
1456		break;
1457	}
1458	default:
1459		break;		/* XXX impossible! */
1460	}
1461
1462	nni6->ni_type = ICMP6_NI_REPLY;
1463	m_freem(m);
1464	return(n);
1465
1466  bad:
1467	m_freem(m);
1468	if (n)
1469		m_freem(n);
1470	return(NULL);
1471}
1472#undef hostnamelen
1473
1474/*
1475 * make a mbuf with DNS-encoded string.  no compression support.
1476 *
1477 * XXX names with less than 2 dots (like "foo" or "foo.section") will be
1478 * treated as truncated name (two \0 at the end).  this is a wild guess.
1479 */
1480static struct mbuf *
1481ni6_nametodns(name, namelen, old)
1482	const char *name;
1483	int namelen;
1484	int old;	/* return pascal string if non-zero */
1485{
1486	struct mbuf *m;
1487	char *cp, *ep;
1488	const char *p, *q;
1489	int i, len, nterm;
1490
1491	if (old)
1492		len = namelen + 1;
1493	else
1494		len = MCLBYTES;
1495
1496	/* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
1497	MGET(m, M_DONTWAIT, MT_DATA);
1498	if (m && len > MLEN) {
1499		MCLGET(m, M_DONTWAIT);
1500		if ((m->m_flags & M_EXT) == 0)
1501			goto fail;
1502	}
1503	if (!m)
1504		goto fail;
1505	m->m_next = NULL;
1506
1507	if (old) {
1508		m->m_len = len;
1509		*mtod(m, char *) = namelen;
1510		bcopy(name, mtod(m, char *) + 1, namelen);
1511		return m;
1512	} else {
1513		m->m_len = 0;
1514		cp = mtod(m, char *);
1515		ep = mtod(m, char *) + M_TRAILINGSPACE(m);
1516
1517		/* if not certain about my name, return empty buffer */
1518		if (namelen == 0)
1519			return m;
1520
1521		/*
1522		 * guess if it looks like shortened hostname, or FQDN.
1523		 * shortened hostname needs two trailing "\0".
1524		 */
1525		i = 0;
1526		for (p = name; p < name + namelen; p++) {
1527			if (*p && *p == '.')
1528				i++;
1529		}
1530		if (i < 2)
1531			nterm = 2;
1532		else
1533			nterm = 1;
1534
1535		p = name;
1536		while (cp < ep && p < name + namelen) {
1537			i = 0;
1538			for (q = p; q < name + namelen && *q && *q != '.'; q++)
1539				i++;
1540			/* result does not fit into mbuf */
1541			if (cp + i + 1 >= ep)
1542				goto fail;
1543			/*
1544			 * DNS label length restriction, RFC1035 page 8.
1545			 * "i == 0" case is included here to avoid returning
1546			 * 0-length label on "foo..bar".
1547			 */
1548			if (i <= 0 || i >= 64)
1549				goto fail;
1550			*cp++ = i;
1551			bcopy(p, cp, i);
1552			cp += i;
1553			p = q;
1554			if (p < name + namelen && *p == '.')
1555				p++;
1556		}
1557		/* termination */
1558		if (cp + nterm >= ep)
1559			goto fail;
1560		while (nterm-- > 0)
1561			*cp++ = '\0';
1562		m->m_len = cp - mtod(m, char *);
1563		return m;
1564	}
1565
1566	panic("should not reach here");
1567	/* NOTREACHED */
1568
1569 fail:
1570	if (m)
1571		m_freem(m);
1572	return NULL;
1573}
1574
1575/*
1576 * check if two DNS-encoded string matches.  takes care of truncated
1577 * form (with \0\0 at the end).  no compression support.
1578 * XXX upper/lowercase match (see RFC2065)
1579 */
1580static int
1581ni6_dnsmatch(a, alen, b, blen)
1582	const char *a;
1583	int alen;
1584	const char *b;
1585	int blen;
1586{
1587	const char *a0, *b0;
1588	int l;
1589
1590	/* simplest case - need validation? */
1591	if (alen == blen && bcmp(a, b, alen) == 0)
1592		return 1;
1593
1594	a0 = a;
1595	b0 = b;
1596
1597	/* termination is mandatory */
1598	if (alen < 2 || blen < 2)
1599		return 0;
1600	if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')
1601		return 0;
1602	alen--;
1603	blen--;
1604
1605	while (a - a0 < alen && b - b0 < blen) {
1606		if (a - a0 + 1 > alen || b - b0 + 1 > blen)
1607			return 0;
1608
1609		if ((signed char)a[0] < 0 || (signed char)b[0] < 0)
1610			return 0;
1611		/* we don't support compression yet */
1612		if (a[0] >= 64 || b[0] >= 64)
1613			return 0;
1614
1615		/* truncated case */
1616		if (a[0] == 0 && a - a0 == alen - 1)
1617			return 1;
1618		if (b[0] == 0 && b - b0 == blen - 1)
1619			return 1;
1620		if (a[0] == 0 || b[0] == 0)
1621			return 0;
1622
1623		if (a[0] != b[0])
1624			return 0;
1625		l = a[0];
1626		if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
1627			return 0;
1628		if (bcmp(a + 1, b + 1, l) != 0)
1629			return 0;
1630
1631		a += 1 + l;
1632		b += 1 + l;
1633	}
1634
1635	if (a - a0 == alen && b - b0 == blen)
1636		return 1;
1637	else
1638		return 0;
1639}
1640
1641/*
1642 * calculate the number of addresses to be returned in the node info reply.
1643 */
1644static int
1645ni6_addrs(ni6, m, ifpp, subj)
1646	struct icmp6_nodeinfo *ni6;
1647	struct mbuf *m;
1648	struct ifnet **ifpp;
1649	char *subj;
1650{
1651	struct ifnet *ifp;
1652	struct in6_ifaddr *ifa6;
1653	struct ifaddr *ifa;
1654	struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
1655	int addrs = 0, addrsofif, iffound = 0;
1656	int niflags = ni6->ni_flags;
1657
1658	if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
1659		switch (ni6->ni_code) {
1660		case ICMP6_NI_SUBJ_IPV6:
1661			if (subj == NULL) /* must be impossible... */
1662				return(0);
1663			subj_ip6 = (struct sockaddr_in6 *)subj;
1664			break;
1665		default:
1666			/*
1667			 * XXX: we only support IPv6 subject address for
1668			 * this Qtype.
1669			 */
1670			return(0);
1671		}
1672	}
1673
1674	for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
1675	{
1676		addrsofif = 0;
1677		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1678		{
1679			if (ifa->ifa_addr->sa_family != AF_INET6)
1680				continue;
1681			ifa6 = (struct in6_ifaddr *)ifa;
1682
1683			if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
1684			    IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
1685					       &ifa6->ia_addr.sin6_addr))
1686				iffound = 1;
1687
1688			/*
1689			 * IPv4-mapped addresses can only be returned by a
1690			 * Node Information proxy, since they represent
1691			 * addresses of IPv4-only nodes, which perforce do
1692			 * not implement this protocol.
1693			 * [icmp-name-lookups-07, Section 5.4]
1694			 * So we don't support NI_NODEADDR_FLAG_COMPAT in
1695			 * this function at this moment.
1696			 */
1697
1698			/* What do we have to do about ::1? */
1699			switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1700			case IPV6_ADDR_SCOPE_LINKLOCAL:
1701				if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
1702					continue;
1703				break;
1704			case IPV6_ADDR_SCOPE_SITELOCAL:
1705				if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
1706					continue;
1707				break;
1708			case IPV6_ADDR_SCOPE_GLOBAL:
1709				if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
1710					continue;
1711				break;
1712			default:
1713				continue;
1714			}
1715
1716			/*
1717			 * check if anycast is okay.
1718			 * XXX: just experimental.  not in the spec.
1719			 */
1720			if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
1721			    (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
1722				continue; /* we need only unicast addresses */
1723			if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
1724			    (icmp6_nodeinfo & 4) == 0) {
1725				continue;
1726			}
1727			addrsofif++; /* count the address */
1728		}
1729		if (iffound) {
1730			*ifpp = ifp;
1731			return(addrsofif);
1732		}
1733
1734		addrs += addrsofif;
1735	}
1736
1737	return(addrs);
1738}
1739
1740static int
1741ni6_store_addrs(ni6, nni6, ifp0, resid)
1742	struct icmp6_nodeinfo *ni6, *nni6;
1743	struct ifnet *ifp0;
1744	int resid;
1745{
1746	struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
1747	struct in6_ifaddr *ifa6;
1748	struct ifaddr *ifa;
1749	struct ifnet *ifp_dep = NULL;
1750	int copied = 0, allow_deprecated = 0;
1751	u_char *cp = (u_char *)(nni6 + 1);
1752	int niflags = ni6->ni_flags;
1753	u_int32_t ltime;
1754
1755	if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
1756		return(0);	/* needless to copy */
1757
1758  again:
1759
1760	for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
1761	{
1762		for (ifa = ifp->if_addrlist.tqh_first; ifa;
1763		     ifa = ifa->ifa_list.tqe_next)
1764		{
1765			if (ifa->ifa_addr->sa_family != AF_INET6)
1766				continue;
1767			ifa6 = (struct in6_ifaddr *)ifa;
1768
1769			if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 &&
1770			    allow_deprecated == 0) {
1771				/*
1772				 * prefererred address should be put before
1773				 * deprecated addresses.
1774				 */
1775
1776				/* record the interface for later search */
1777				if (ifp_dep == NULL)
1778					ifp_dep = ifp;
1779
1780				continue;
1781			}
1782			else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 &&
1783				 allow_deprecated != 0)
1784				continue; /* we now collect deprecated addrs */
1785
1786			/* What do we have to do about ::1? */
1787			switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1788			case IPV6_ADDR_SCOPE_LINKLOCAL:
1789				if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
1790					continue;
1791				break;
1792			case IPV6_ADDR_SCOPE_SITELOCAL:
1793				if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
1794					continue;
1795				break;
1796			case IPV6_ADDR_SCOPE_GLOBAL:
1797				if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
1798					continue;
1799				break;
1800			default:
1801				continue;
1802			}
1803
1804			/*
1805			 * check if anycast is okay.
1806			 * XXX: just experimental. not in the spec.
1807			 */
1808			if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
1809			    (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
1810				continue;
1811			if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
1812			    (icmp6_nodeinfo & 4) == 0) {
1813				continue;
1814			}
1815
1816			/* now we can copy the address */
1817			if (resid < sizeof(struct in6_addr) +
1818			    sizeof(u_int32_t)) {
1819				/*
1820				 * We give up much more copy.
1821				 * Set the truncate flag and return.
1822				 */
1823				nni6->ni_flags |=
1824					NI_NODEADDR_FLAG_TRUNCATE;
1825				return(copied);
1826			}
1827
1828			/*
1829			 * Set the TTL of the address.
1830			 * The TTL value should be one of the following
1831			 * according to the specification:
1832			 *
1833			 * 1. The remaining lifetime of a DHCP lease on the
1834			 *    address, or
1835			 * 2. The remaining Valid Lifetime of a prefix from
1836			 *    which the address was derived through Stateless
1837			 *    Autoconfiguration.
1838			 *
1839			 * Note that we currently do not support stateful
1840			 * address configuration by DHCPv6, so the former
1841			 * case can't happen.
1842			 */
1843			if (ifa6->ia6_lifetime.ia6t_expire == 0)
1844				ltime = ND6_INFINITE_LIFETIME;
1845			else {
1846				if (ifa6->ia6_lifetime.ia6t_expire >
1847				    time_second)
1848					ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second);
1849				else
1850					ltime = 0;
1851			}
1852
1853			bcopy(&ltime, cp, sizeof(u_int32_t));
1854			cp += sizeof(u_int32_t);
1855
1856			/* copy the address itself */
1857			bcopy(&ifa6->ia_addr.sin6_addr, cp,
1858			      sizeof(struct in6_addr));
1859			/* XXX: KAME link-local hack; remove ifindex */
1860			if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
1861				((struct in6_addr *)cp)->s6_addr16[1] = 0;
1862			cp += sizeof(struct in6_addr);
1863
1864			resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t));
1865			copied += (sizeof(struct in6_addr) +
1866				   sizeof(u_int32_t));
1867		}
1868		if (ifp0)	/* we need search only on the specified IF */
1869			break;
1870	}
1871
1872	if (allow_deprecated == 0 && ifp_dep != NULL) {
1873		ifp = ifp_dep;
1874		allow_deprecated = 1;
1875
1876		goto again;
1877	}
1878
1879	return(copied);
1880}
1881
1882/*
1883 * XXX almost dup'ed code with rip6_input.
1884 */
1885static int
1886icmp6_rip6_input(mp, off)
1887	struct	mbuf **mp;
1888	int	off;
1889{
1890	struct mbuf *m = *mp;
1891	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1892	struct in6pcb *in6p;
1893	struct in6pcb *last = NULL;
1894	struct sockaddr_in6 rip6src;
1895	struct icmp6_hdr *icmp6;
1896	struct mbuf *opts = NULL;
1897
1898#ifndef PULLDOWN_TEST
1899	/* this is assumed to be safe. */
1900	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
1901#else
1902	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
1903	if (icmp6 == NULL) {
1904		/* m is already reclaimed */
1905		return IPPROTO_DONE;
1906	}
1907#endif
1908
1909	bzero(&rip6src, sizeof(rip6src));
1910	rip6src.sin6_len = sizeof(struct sockaddr_in6);
1911	rip6src.sin6_family = AF_INET6;
1912	/* KAME hack: recover scopeid */
1913	(void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
1914
1915	LIST_FOREACH(in6p, &ripcb, inp_list)
1916	{
1917		if ((in6p->inp_vflag & INP_IPV6) == 0)
1918			continue;
1919#ifdef HAVE_NRL_INPCB
1920		if (!(in6p->in6p_flags & INP_IPV6))
1921			continue;
1922#endif
1923		if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
1924			continue;
1925		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1926		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1927			continue;
1928		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1929		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1930			continue;
1931		if (in6p->in6p_icmp6filt
1932		    && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
1933				 in6p->in6p_icmp6filt))
1934			continue;
1935		if (last) {
1936			struct	mbuf *n;
1937			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
1938				if (last->in6p_flags & IN6P_CONTROLOPTS)
1939					ip6_savecontrol(last, &opts, ip6, n);
1940				/* strip intermediate headers */
1941				m_adj(n, off);
1942				if (sbappendaddr(&last->in6p_socket->so_rcv,
1943						 (struct sockaddr *)&rip6src,
1944						 n, opts) == 0) {
1945					/* should notify about lost packet */
1946					m_freem(n);
1947					if (opts) {
1948						m_freem(opts);
1949					}
1950				} else
1951					sorwakeup(last->in6p_socket);
1952				opts = NULL;
1953			}
1954		}
1955		last = in6p;
1956	}
1957	if (last) {
1958		if (last->in6p_flags & IN6P_CONTROLOPTS)
1959			ip6_savecontrol(last, &opts, ip6, m);
1960		/* strip intermediate headers */
1961		m_adj(m, off);
1962		if (sbappendaddr(&last->in6p_socket->so_rcv,
1963				 (struct sockaddr *)&rip6src, m, opts) == 0) {
1964			m_freem(m);
1965			if (opts)
1966				m_freem(opts);
1967		} else
1968			sorwakeup(last->in6p_socket);
1969	} else {
1970		m_freem(m);
1971		ip6stat.ip6s_delivered--;
1972	}
1973	return IPPROTO_DONE;
1974}
1975
1976/*
1977 * Reflect the ip6 packet back to the source.
1978 * OFF points to the icmp6 header, counted from the top of the mbuf.
1979 */
1980void
1981icmp6_reflect(m, off)
1982	struct	mbuf *m;
1983	size_t off;
1984{
1985	struct ip6_hdr *ip6;
1986	struct icmp6_hdr *icmp6;
1987	struct in6_ifaddr *ia;
1988	struct in6_addr t, *src = 0;
1989	int plen;
1990	int type, code;
1991	struct ifnet *outif = NULL;
1992	struct sockaddr_in6 sa6_src, sa6_dst;
1993#ifdef COMPAT_RFC1885
1994	int mtu = IPV6_MMTU;
1995	struct sockaddr_in6 *sin6 = &icmp6_reflect_rt.ro_dst;
1996#endif
1997
1998	/* too short to reflect */
1999	if (off < sizeof(struct ip6_hdr)) {
2000		nd6log((LOG_DEBUG,
2001		    "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
2002		    (u_long)off, (u_long)sizeof(struct ip6_hdr),
2003		    __FILE__, __LINE__));
2004		goto bad;
2005	}
2006
2007	/*
2008	 * If there are extra headers between IPv6 and ICMPv6, strip
2009	 * off that header first.
2010	 */
2011#ifdef DIAGNOSTIC
2012	if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
2013		panic("assumption failed in icmp6_reflect");
2014#endif
2015	if (off > sizeof(struct ip6_hdr)) {
2016		size_t l;
2017		struct ip6_hdr nip6;
2018
2019		l = off - sizeof(struct ip6_hdr);
2020		m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
2021		m_adj(m, l);
2022		l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2023		if (m->m_len < l) {
2024			if ((m = m_pullup(m, l)) == NULL)
2025				return;
2026		}
2027		bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
2028	} else /* off == sizeof(struct ip6_hdr) */ {
2029		size_t l;
2030		l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2031		if (m->m_len < l) {
2032			if ((m = m_pullup(m, l)) == NULL)
2033				return;
2034		}
2035	}
2036	plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
2037	ip6 = mtod(m, struct ip6_hdr *);
2038	ip6->ip6_nxt = IPPROTO_ICMPV6;
2039	icmp6 = (struct icmp6_hdr *)(ip6 + 1);
2040	type = icmp6->icmp6_type; /* keep type for statistics */
2041	code = icmp6->icmp6_code; /* ditto. */
2042
2043	t = ip6->ip6_dst;
2044	/*
2045	 * ip6_input() drops a packet if its src is multicast.
2046	 * So, the src is never multicast.
2047	 */
2048	ip6->ip6_dst = ip6->ip6_src;
2049
2050	/*
2051	 * XXX: make sure to embed scope zone information, using
2052	 * already embedded IDs or the received interface (if any).
2053	 * Note that rcvif may be NULL.
2054	 * TODO: scoped routing case (XXX).
2055	 */
2056	bzero(&sa6_src, sizeof(sa6_src));
2057	sa6_src.sin6_family = AF_INET6;
2058	sa6_src.sin6_len = sizeof(sa6_src);
2059	sa6_src.sin6_addr = ip6->ip6_dst;
2060	in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
2061	in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL);
2062	bzero(&sa6_dst, sizeof(sa6_dst));
2063	sa6_dst.sin6_family = AF_INET6;
2064	sa6_dst.sin6_len = sizeof(sa6_dst);
2065	sa6_dst.sin6_addr = t;
2066	in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
2067	in6_embedscope(&t, &sa6_dst, NULL, NULL);
2068
2069#ifdef COMPAT_RFC1885
2070	/*
2071	 * xxx guess MTU
2072	 * RFC 1885 requires that echo reply should be truncated if it
2073	 * does not fit in with (return) path MTU, but the description was
2074	 * removed in the new spec.
2075	 */
2076	if (icmp6_reflect_rt.ro_rt == 0 ||
2077	    ! (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_dst))) {
2078		if (icmp6_reflect_rt.ro_rt) {
2079			RTFREE(icmp6_reflect_rt.ro_rt);
2080			icmp6_reflect_rt.ro_rt = 0;
2081		}
2082		bzero(sin6, sizeof(*sin6));
2083		sin6->sin6_family = PF_INET6;
2084		sin6->sin6_len = sizeof(struct sockaddr_in6);
2085		sin6->sin6_addr = ip6->ip6_dst;
2086
2087		rtalloc_ign((struct route *)&icmp6_reflect_rt.ro_rt,
2088			    RTF_PRCLONING);
2089	}
2090
2091	if (icmp6_reflect_rt.ro_rt == 0)
2092		goto bad;
2093
2094	if ((icmp6_reflect_rt.ro_rt->rt_flags & RTF_HOST)
2095	    && mtu < icmp6_reflect_rt.ro_rt->rt_ifp->if_mtu)
2096		mtu = icmp6_reflect_rt.ro_rt->rt_rmx.rmx_mtu;
2097
2098	if (mtu < m->m_pkthdr.len) {
2099		plen -= (m->m_pkthdr.len - mtu);
2100		m_adj(m, mtu - m->m_pkthdr.len);
2101	}
2102#endif
2103	/*
2104	 * If the incoming packet was addressed directly to us(i.e. unicast),
2105	 * use dst as the src for the reply.
2106	 * The IN6_IFF_NOTREADY case would be VERY rare, but is possible
2107	 * (for example) when we encounter an error while forwarding procedure
2108	 * destined to a duplicated address of ours.
2109	 */
2110	for (ia = in6_ifaddr; ia; ia = ia->ia_next)
2111		if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
2112		    (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
2113			src = &t;
2114			break;
2115		}
2116	if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
2117		/*
2118		 * This is the case if the dst is our link-local address
2119		 * and the sender is also ourselves.
2120		 */
2121		src = &t;
2122	}
2123
2124	if (src == 0) {
2125		int e;
2126		struct route_in6 ro;
2127
2128		/*
2129		 * This case matches to multicasts, our anycast, or unicasts
2130		 * that we do not own.  Select a source address based on the
2131		 * source address of the erroneous packet.
2132		 */
2133		bzero(&ro, sizeof(ro));
2134		src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e);
2135		if (ro.ro_rt)
2136			RTFREE(ro.ro_rt); /* XXX: we could use this */
2137		if (src == NULL) {
2138			nd6log((LOG_DEBUG,
2139			    "icmp6_reflect: source can't be determined: "
2140			    "dst=%s, error=%d\n",
2141			    ip6_sprintf(&sa6_src.sin6_addr), e));
2142			goto bad;
2143		}
2144	}
2145
2146	ip6->ip6_src = *src;
2147
2148	ip6->ip6_flow = 0;
2149	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2150	ip6->ip6_vfc |= IPV6_VERSION;
2151	ip6->ip6_nxt = IPPROTO_ICMPV6;
2152	if (m->m_pkthdr.rcvif) {
2153		/* XXX: This may not be the outgoing interface */
2154		ip6->ip6_hlim = nd_ifinfo[m->m_pkthdr.rcvif->if_index].chlim;
2155	} else
2156		ip6->ip6_hlim = ip6_defhlim;
2157
2158	icmp6->icmp6_cksum = 0;
2159	icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
2160					sizeof(struct ip6_hdr), plen);
2161
2162	/*
2163	 * XXX option handling
2164	 */
2165
2166	m->m_flags &= ~(M_BCAST|M_MCAST);
2167
2168#ifdef COMPAT_RFC1885
2169	ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif, NULL);
2170#else
2171	ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
2172#endif
2173	if (outif)
2174		icmp6_ifoutstat_inc(outif, type, code);
2175
2176	return;
2177
2178 bad:
2179	m_freem(m);
2180	return;
2181}
2182
2183void
2184icmp6_fasttimo()
2185{
2186
2187	mld6_fasttimeo();
2188}
2189
2190static const char *
2191icmp6_redirect_diag(src6, dst6, tgt6)
2192	struct in6_addr *src6;
2193	struct in6_addr *dst6;
2194	struct in6_addr *tgt6;
2195{
2196	static char buf[1024];
2197	snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
2198		ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
2199	return buf;
2200}
2201
2202void
2203icmp6_redirect_input(m, off)
2204	struct mbuf *m;
2205	int off;
2206{
2207	struct ifnet *ifp = m->m_pkthdr.rcvif;
2208	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2209	struct nd_redirect *nd_rd;
2210	int icmp6len = ntohs(ip6->ip6_plen);
2211	char *lladdr = NULL;
2212	int lladdrlen = 0;
2213	u_char *redirhdr = NULL;
2214	int redirhdrlen = 0;
2215	struct rtentry *rt = NULL;
2216	int is_router;
2217	int is_onlink;
2218	struct in6_addr src6 = ip6->ip6_src;
2219	struct in6_addr redtgt6;
2220	struct in6_addr reddst6;
2221	union nd_opts ndopts;
2222
2223	if (!m || !ifp)
2224		return;
2225
2226	/* XXX if we are router, we don't update route by icmp6 redirect */
2227	if (ip6_forwarding)
2228		goto freeit;
2229	if (!icmp6_rediraccept)
2230		goto freeit;
2231
2232#ifndef PULLDOWN_TEST
2233	IP6_EXTHDR_CHECK(m, off, icmp6len,);
2234	nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
2235#else
2236	IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
2237	if (nd_rd == NULL) {
2238		icmp6stat.icp6s_tooshort++;
2239		return;
2240	}
2241#endif
2242	redtgt6 = nd_rd->nd_rd_target;
2243	reddst6 = nd_rd->nd_rd_dst;
2244
2245	if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
2246		redtgt6.s6_addr16[1] = htons(ifp->if_index);
2247	if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
2248		reddst6.s6_addr16[1] = htons(ifp->if_index);
2249
2250	/* validation */
2251	if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
2252		nd6log((LOG_ERR,
2253			"ICMP6 redirect sent from %s rejected; "
2254			"must be from linklocal\n", ip6_sprintf(&src6)));
2255		goto bad;
2256	}
2257	if (ip6->ip6_hlim != 255) {
2258		nd6log((LOG_ERR,
2259			"ICMP6 redirect sent from %s rejected; "
2260			"hlim=%d (must be 255)\n",
2261			ip6_sprintf(&src6), ip6->ip6_hlim));
2262		goto bad;
2263	}
2264    {
2265	/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
2266	struct sockaddr_in6 sin6;
2267	struct in6_addr *gw6;
2268
2269	bzero(&sin6, sizeof(sin6));
2270	sin6.sin6_family = AF_INET6;
2271	sin6.sin6_len = sizeof(struct sockaddr_in6);
2272	bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
2273	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
2274	if (rt) {
2275		if (rt->rt_gateway == NULL ||
2276		    rt->rt_gateway->sa_family != AF_INET6) {
2277			nd6log((LOG_ERR,
2278			    "ICMP6 redirect rejected; no route "
2279			    "with inet6 gateway found for redirect dst: %s\n",
2280			    icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2281			RTFREE(rt);
2282			goto bad;
2283		}
2284
2285		gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
2286		if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
2287			nd6log((LOG_ERR,
2288				"ICMP6 redirect rejected; "
2289				"not equal to gw-for-src=%s (must be same): "
2290				"%s\n",
2291				ip6_sprintf(gw6),
2292				icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2293			RTFREE(rt);
2294			goto bad;
2295		}
2296	} else {
2297		nd6log((LOG_ERR,
2298			"ICMP6 redirect rejected; "
2299			"no route found for redirect dst: %s\n",
2300			icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2301		goto bad;
2302	}
2303	RTFREE(rt);
2304	rt = NULL;
2305    }
2306	if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
2307		nd6log((LOG_ERR,
2308			"ICMP6 redirect rejected; "
2309			"redirect dst must be unicast: %s\n",
2310			icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2311		goto bad;
2312	}
2313
2314	is_router = is_onlink = 0;
2315	if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
2316		is_router = 1;	/* router case */
2317	if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
2318		is_onlink = 1;	/* on-link destination case */
2319	if (!is_router && !is_onlink) {
2320		nd6log((LOG_ERR,
2321			"ICMP6 redirect rejected; "
2322			"neither router case nor onlink case: %s\n",
2323			icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2324		goto bad;
2325	}
2326	/* validation passed */
2327
2328	icmp6len -= sizeof(*nd_rd);
2329	nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
2330	if (nd6_options(&ndopts) < 0) {
2331		nd6log((LOG_INFO, "icmp6_redirect_input: "
2332			"invalid ND option, rejected: %s\n",
2333			icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2334		/* nd6_options have incremented stats */
2335		goto freeit;
2336	}
2337
2338	if (ndopts.nd_opts_tgt_lladdr) {
2339		lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
2340		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
2341	}
2342
2343	if (ndopts.nd_opts_rh) {
2344		redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
2345		redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
2346	}
2347
2348	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
2349		nd6log((LOG_INFO,
2350			"icmp6_redirect_input: lladdrlen mismatch for %s "
2351			"(if %d, icmp6 packet %d): %s\n",
2352			ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
2353			icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2354		goto bad;
2355	}
2356
2357	/* RFC 2461 8.3 */
2358	nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
2359			 is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
2360
2361	if (!is_onlink) {	/* better router case.  perform rtredirect. */
2362		/* perform rtredirect */
2363		struct sockaddr_in6 sdst;
2364		struct sockaddr_in6 sgw;
2365		struct sockaddr_in6 ssrc;
2366
2367		bzero(&sdst, sizeof(sdst));
2368		bzero(&sgw, sizeof(sgw));
2369		bzero(&ssrc, sizeof(ssrc));
2370		sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
2371		sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
2372			sizeof(struct sockaddr_in6);
2373		bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
2374		bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2375		bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
2376		rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
2377			   (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
2378			   (struct sockaddr *)&ssrc,
2379			   (struct rtentry **)NULL);
2380	}
2381	/* finally update cached route in each socket via pfctlinput */
2382    {
2383	struct sockaddr_in6 sdst;
2384
2385	bzero(&sdst, sizeof(sdst));
2386	sdst.sin6_family = AF_INET6;
2387	sdst.sin6_len = sizeof(struct sockaddr_in6);
2388	bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2389	pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
2390#ifdef IPSEC
2391	key_sa_routechange((struct sockaddr *)&sdst);
2392#endif
2393    }
2394
2395 freeit:
2396	m_freem(m);
2397	return;
2398
2399 bad:
2400	icmp6stat.icp6s_badredirect++;
2401	m_freem(m);
2402}
2403
2404void
2405icmp6_redirect_output(m0, rt)
2406	struct mbuf *m0;
2407	struct rtentry *rt;
2408{
2409	struct ifnet *ifp;	/* my outgoing interface */
2410	struct in6_addr *ifp_ll6;
2411	struct in6_addr *router_ll6;
2412	struct ip6_hdr *sip6;	/* m0 as struct ip6_hdr */
2413	struct mbuf *m = NULL;	/* newly allocated one */
2414	struct ip6_hdr *ip6;	/* m as struct ip6_hdr */
2415	struct nd_redirect *nd_rd;
2416	size_t maxlen;
2417	u_char *p;
2418	struct ifnet *outif = NULL;
2419	struct sockaddr_in6 src_sa;
2420
2421	icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
2422
2423	/* if we are not router, we don't send icmp6 redirect */
2424	if (!ip6_forwarding || ip6_accept_rtadv)
2425		goto fail;
2426
2427	/* sanity check */
2428	if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
2429		goto fail;
2430
2431	/*
2432	 * Address check:
2433	 *  the source address must identify a neighbor, and
2434	 *  the destination address must not be a multicast address
2435	 *  [RFC 2461, sec 8.2]
2436	 */
2437	sip6 = mtod(m0, struct ip6_hdr *);
2438	bzero(&src_sa, sizeof(src_sa));
2439	src_sa.sin6_family = AF_INET6;
2440	src_sa.sin6_len = sizeof(src_sa);
2441	src_sa.sin6_addr = sip6->ip6_src;
2442	/* we don't currently use sin6_scope_id, but eventually use it */
2443	src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
2444	if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
2445		goto fail;
2446	if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
2447		goto fail;	/* what should we do here? */
2448
2449	/* rate limit */
2450	if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
2451		goto fail;
2452
2453	/*
2454	 * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
2455	 * we almost always ask for an mbuf cluster for simplicity.
2456	 * (MHLEN < IPV6_MMTU is almost always true)
2457	 */
2458#if IPV6_MMTU >= MCLBYTES
2459# error assumption failed about IPV6_MMTU and MCLBYTES
2460#endif
2461	MGETHDR(m, M_DONTWAIT, MT_HEADER);
2462	if (m && IPV6_MMTU >= MHLEN)
2463		MCLGET(m, M_DONTWAIT);
2464	if (!m)
2465		goto fail;
2466	m->m_pkthdr.rcvif = NULL;
2467	m->m_len = 0;
2468	maxlen = M_TRAILINGSPACE(m);
2469	maxlen = min(IPV6_MMTU, maxlen);
2470	/* just for safety */
2471	if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
2472	    ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
2473		goto fail;
2474	}
2475
2476	{
2477		/* get ip6 linklocal address for ifp(my outgoing interface). */
2478		struct in6_ifaddr *ia;
2479		if ((ia = in6ifa_ifpforlinklocal(ifp,
2480						 IN6_IFF_NOTREADY|
2481						 IN6_IFF_ANYCAST)) == NULL)
2482			goto fail;
2483		ifp_ll6 = &ia->ia_addr.sin6_addr;
2484	}
2485
2486	/* get ip6 linklocal address for the router. */
2487	if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
2488		struct sockaddr_in6 *sin6;
2489		sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
2490		router_ll6 = &sin6->sin6_addr;
2491		if (!IN6_IS_ADDR_LINKLOCAL(router_ll6))
2492			router_ll6 = (struct in6_addr *)NULL;
2493	} else
2494		router_ll6 = (struct in6_addr *)NULL;
2495
2496	/* ip6 */
2497	ip6 = mtod(m, struct ip6_hdr *);
2498	ip6->ip6_flow = 0;
2499	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2500	ip6->ip6_vfc |= IPV6_VERSION;
2501	/* ip6->ip6_plen will be set later */
2502	ip6->ip6_nxt = IPPROTO_ICMPV6;
2503	ip6->ip6_hlim = 255;
2504	/* ip6->ip6_src must be linklocal addr for my outgoing if. */
2505	bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
2506	bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
2507
2508	/* ND Redirect */
2509	nd_rd = (struct nd_redirect *)(ip6 + 1);
2510	nd_rd->nd_rd_type = ND_REDIRECT;
2511	nd_rd->nd_rd_code = 0;
2512	nd_rd->nd_rd_reserved = 0;
2513	if (rt->rt_flags & RTF_GATEWAY) {
2514		/*
2515		 * nd_rd->nd_rd_target must be a link-local address in
2516		 * better router cases.
2517		 */
2518		if (!router_ll6)
2519			goto fail;
2520		bcopy(router_ll6, &nd_rd->nd_rd_target,
2521		      sizeof(nd_rd->nd_rd_target));
2522		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2523		      sizeof(nd_rd->nd_rd_dst));
2524	} else {
2525		/* make sure redtgt == reddst */
2526		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
2527		      sizeof(nd_rd->nd_rd_target));
2528		bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2529		      sizeof(nd_rd->nd_rd_dst));
2530	}
2531
2532	p = (u_char *)(nd_rd + 1);
2533
2534	if (!router_ll6)
2535		goto nolladdropt;
2536
2537    {
2538	/* target lladdr option */
2539	struct rtentry *rt_router = NULL;
2540	int len;
2541	struct sockaddr_dl *sdl;
2542	struct nd_opt_hdr *nd_opt;
2543	char *lladdr;
2544
2545	rt_router = nd6_lookup(router_ll6, 0, ifp);
2546	if (!rt_router)
2547		goto nolladdropt;
2548	len = sizeof(*nd_opt) + ifp->if_addrlen;
2549	len = (len + 7) & ~7;	/* round by 8 */
2550	/* safety check */
2551	if (len + (p - (u_char *)ip6) > maxlen)
2552		goto nolladdropt;
2553	if (!(rt_router->rt_flags & RTF_GATEWAY) &&
2554	    (rt_router->rt_flags & RTF_LLINFO) &&
2555	    (rt_router->rt_gateway->sa_family == AF_LINK) &&
2556	    (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) &&
2557	    sdl->sdl_alen) {
2558		nd_opt = (struct nd_opt_hdr *)p;
2559		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
2560		nd_opt->nd_opt_len = len >> 3;
2561		lladdr = (char *)(nd_opt + 1);
2562		bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
2563		p += len;
2564	}
2565    }
2566nolladdropt:;
2567
2568	m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2569
2570	/* just to be safe */
2571#ifdef M_DECRYPTED	/*not openbsd*/
2572	if (m0->m_flags & M_DECRYPTED)
2573		goto noredhdropt;
2574#endif
2575	if (p - (u_char *)ip6 > maxlen)
2576		goto noredhdropt;
2577
2578    {
2579	/* redirected header option */
2580	int len;
2581	struct nd_opt_rd_hdr *nd_opt_rh;
2582
2583	/*
2584	 * compute the maximum size for icmp6 redirect header option.
2585	 * XXX room for auth header?
2586	 */
2587	len = maxlen - (p - (u_char *)ip6);
2588	len &= ~7;
2589
2590	/* This is just for simplicity. */
2591	if (m0->m_pkthdr.len != m0->m_len) {
2592		if (m0->m_next) {
2593			m_freem(m0->m_next);
2594			m0->m_next = NULL;
2595		}
2596		m0->m_pkthdr.len = m0->m_len;
2597	}
2598
2599	/*
2600	 * Redirected header option spec (RFC2461 4.6.3) talks nothing
2601	 * about padding/truncate rule for the original IP packet.
2602	 * From the discussion on IPv6imp in Feb 1999, the consensus was:
2603	 * - "attach as much as possible" is the goal
2604	 * - pad if not aligned (original size can be guessed by original
2605	 *   ip6 header)
2606	 * Following code adds the padding if it is simple enough,
2607	 * and truncates if not.
2608	 */
2609	if (m0->m_next || m0->m_pkthdr.len != m0->m_len)
2610		panic("assumption failed in %s:%d\n", __FILE__, __LINE__);
2611
2612	if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
2613		/* not enough room, truncate */
2614		m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2615	} else {
2616		/* enough room, pad or truncate */
2617		size_t extra;
2618
2619		extra = m0->m_pkthdr.len % 8;
2620		if (extra) {
2621			/* pad if easy enough, truncate if not */
2622			if (8 - extra <= M_TRAILINGSPACE(m0)) {
2623				/* pad */
2624				m0->m_len += (8 - extra);
2625				m0->m_pkthdr.len += (8 - extra);
2626			} else {
2627				/* truncate */
2628				m0->m_pkthdr.len -= extra;
2629				m0->m_len -= extra;
2630			}
2631		}
2632		len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
2633		m0->m_pkthdr.len = m0->m_len = len - sizeof(*nd_opt_rh);
2634	}
2635
2636	nd_opt_rh = (struct nd_opt_rd_hdr *)p;
2637	bzero(nd_opt_rh, sizeof(*nd_opt_rh));
2638	nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
2639	nd_opt_rh->nd_opt_rh_len = len >> 3;
2640	p += sizeof(*nd_opt_rh);
2641	m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2642
2643	/* connect m0 to m */
2644	m->m_next = m0;
2645	m->m_pkthdr.len = m->m_len + m0->m_len;
2646    }
2647noredhdropt:;
2648
2649	if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
2650		sip6->ip6_src.s6_addr16[1] = 0;
2651	if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
2652		sip6->ip6_dst.s6_addr16[1] = 0;
2653#if 0
2654	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
2655		ip6->ip6_src.s6_addr16[1] = 0;
2656	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
2657		ip6->ip6_dst.s6_addr16[1] = 0;
2658#endif
2659	if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
2660		nd_rd->nd_rd_target.s6_addr16[1] = 0;
2661	if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
2662		nd_rd->nd_rd_dst.s6_addr16[1] = 0;
2663
2664	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
2665
2666	nd_rd->nd_rd_cksum = 0;
2667	nd_rd->nd_rd_cksum
2668		= in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
2669
2670	/* send the packet to outside... */
2671	ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
2672	if (outif) {
2673		icmp6_ifstat_inc(outif, ifs6_out_msg);
2674		icmp6_ifstat_inc(outif, ifs6_out_redirect);
2675	}
2676	icmp6stat.icp6s_outhist[ND_REDIRECT]++;
2677
2678	return;
2679
2680fail:
2681	if (m)
2682		m_freem(m);
2683	if (m0)
2684		m_freem(m0);
2685}
2686
2687#ifdef HAVE_NRL_INPCB
2688#define sotoin6pcb	sotoinpcb
2689#define in6pcb		inpcb
2690#define in6p_icmp6filt	inp_icmp6filt
2691#endif
2692/*
2693 * ICMPv6 socket option processing.
2694 */
2695int
2696icmp6_ctloutput(so, sopt)
2697	struct socket *so;
2698	struct sockopt *sopt;
2699{
2700	int error = 0;
2701	int optlen;
2702	struct inpcb *inp = sotoinpcb(so);
2703	int level, op, optname;
2704
2705	if (sopt) {
2706		level = sopt->sopt_level;
2707		op = sopt->sopt_dir;
2708		optname = sopt->sopt_name;
2709		optlen = sopt->sopt_valsize;
2710	} else
2711		level = op = optname = optlen = 0;
2712
2713	if (level != IPPROTO_ICMPV6) {
2714		return EINVAL;
2715	}
2716
2717	switch (op) {
2718	case PRCO_SETOPT:
2719		switch (optname) {
2720		case ICMP6_FILTER:
2721		    {
2722			struct icmp6_filter *p;
2723
2724			if (optlen != sizeof(*p)) {
2725				error = EMSGSIZE;
2726				break;
2727			}
2728			if (inp->in6p_icmp6filt == NULL) {
2729				error = EINVAL;
2730				break;
2731			}
2732			error = sooptcopyin(sopt, inp->in6p_icmp6filt, optlen,
2733				optlen);
2734			break;
2735		    }
2736
2737		default:
2738			error = ENOPROTOOPT;
2739			break;
2740		}
2741		break;
2742
2743	case PRCO_GETOPT:
2744		switch (optname) {
2745		case ICMP6_FILTER:
2746		    {
2747			if (inp->in6p_icmp6filt == NULL) {
2748				error = EINVAL;
2749				break;
2750			}
2751			error = sooptcopyout(sopt, inp->in6p_icmp6filt,
2752				sizeof(struct icmp6_filter));
2753			break;
2754		    }
2755
2756		default:
2757			error = ENOPROTOOPT;
2758			break;
2759		}
2760		break;
2761	}
2762
2763	return(error);
2764}
2765#ifdef HAVE_NRL_INPCB
2766#undef sotoin6pcb
2767#undef in6pcb
2768#undef in6p_icmp6filt
2769#endif
2770
2771#ifndef HAVE_PPSRATECHECK
2772#ifndef timersub
2773#define	timersub(tvp, uvp, vvp)						\
2774	do {								\
2775		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
2776		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
2777		if ((vvp)->tv_usec < 0) {				\
2778			(vvp)->tv_sec--;				\
2779			(vvp)->tv_usec += 1000000;			\
2780		}							\
2781	} while (0)
2782#endif
2783
2784/*
2785 * ppsratecheck(): packets (or events) per second limitation.
2786 */
2787static int
2788ppsratecheck(lasttime, curpps, maxpps)
2789	struct timeval *lasttime;
2790	int *curpps;
2791	int maxpps;	/* maximum pps allowed */
2792{
2793	struct timeval tv, delta;
2794	int s, rv;
2795
2796	s = splclock();
2797	microtime(&tv);
2798	splx(s);
2799
2800	timersub(&tv, lasttime, &delta);
2801
2802	/*
2803	 * Check for 0,0 so that the message will be seen at least once.
2804	 * If more than one second has passed since the last update of
2805	 * lasttime, reset the counter.
2806	 *
2807	 * We do increment *curpps even in *curpps < maxpps case, as some may
2808	 * try to use *curpps for stat purposes as well.
2809	 */
2810	if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
2811	    delta.tv_sec >= 1) {
2812		*lasttime = tv;
2813		*curpps = 0;
2814		rv = 1;
2815	} else if (maxpps < 0)
2816		rv = 1;
2817	else if (*curpps < maxpps)
2818		rv = 1;
2819	else
2820		rv = 0;
2821
2822#if 1 /* DIAGNOSTIC? */
2823	/* be careful about wrap-around */
2824	if (*curpps + 1 > *curpps)
2825		*curpps = *curpps + 1;
2826#else
2827	/*
2828	 * assume that there's not too many calls to this function.
2829	 * not sure if the assumption holds, as it depends on *caller's*
2830	 * behavior, not the behavior of this function.
2831	 * IMHO it is wrong to make assumption on the caller's behavior,
2832	 * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
2833	 */
2834	*curpps = *curpps + 1;
2835#endif
2836
2837	return (rv);
2838}
2839#endif
2840
2841/*
2842 * Perform rate limit check.
2843 * Returns 0 if it is okay to send the icmp6 packet.
2844 * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
2845 * limitation.
2846 *
2847 * XXX per-destination/type check necessary?
2848 */
2849static int
2850icmp6_ratelimit(dst, type, code)
2851	const struct in6_addr *dst;	/* not used at this moment */
2852	const int type;			/* not used at this moment */
2853	const int code;			/* not used at this moment */
2854{
2855	int ret;
2856
2857	ret = 0;	/* okay to send */
2858
2859	/* PPS limit */
2860	if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
2861	    icmp6errppslim)) {
2862		/* The packet is subject to rate limit */
2863		ret++;
2864	}
2865
2866	return ret;
2867}
2868