xref: /openbsd-src/sys/netinet6/in6_pcb.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1 /*	$OpenBSD: in6_pcb.c,v 1.42 2004/02/06 21:05:57 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	1.1 (NRL) 17 January 1995
34  *
35  * NRL grants permission for redistribution and use in source and binary
36  * forms, with or without modification, of the software and documentation
37  * created at NRL provided that the following conditions are met:
38  *
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 acknowledgements:
46  * 	This product includes software developed by the University of
47  * 	California, Berkeley and its contributors.
48  * 	This product includes software developed at the Information
49  * 	Technology Division, US Naval Research Laboratory.
50  * 4. Neither the name of the NRL nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
55  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
57  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
58  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  *
66  * The views and conclusions contained in the software and documentation
67  * are those of the authors and should not be interpreted as representing
68  * official policies, either expressed or implied, of the US Naval
69  * Research Laboratory (NRL).
70  */
71 
72 /*
73  * Copyright (c) 1982, 1986, 1990, 1993, 1995
74  *	Regents of the University of California.  All rights reserved.
75  *
76  * Redistribution and use in source and binary forms, with or without
77  * modification, are permitted provided that the following conditions
78  * are met:
79  * 1. Redistributions of source code must retain the above copyright
80  *    notice, this list of conditions and the following disclaimer.
81  * 2. Redistributions in binary form must reproduce the above copyright
82  *    notice, this list of conditions and the following disclaimer in the
83  *    documentation and/or other materials provided with the distribution.
84  * 3. Neither the name of the University nor the names of its contributors
85  *    may be used to endorse or promote products derived from this software
86  *    without specific prior written permission.
87  *
88  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
89  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
92  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98  * SUCH DAMAGE.
99  *
100  */
101 
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/malloc.h>
105 #include <sys/mbuf.h>
106 #include <sys/domain.h>
107 #include <sys/protosw.h>
108 #include <sys/socket.h>
109 #include <sys/socketvar.h>
110 #include <sys/errno.h>
111 #include <sys/time.h>
112 #include <sys/proc.h>
113 
114 #include <net/if.h>
115 #include <net/route.h>
116 
117 #include <netinet/in.h>
118 #include <netinet/in_systm.h>
119 #include <netinet/ip.h>
120 #include <netinet/in_pcb.h>
121 
122 #include <netinet6/in6_var.h>
123 #include <netinet/ip6.h>
124 #include <netinet6/ip6_var.h>
125 
126 /*
127  * External globals
128  */
129 
130 #include <dev/rndvar.h>
131 
132 extern struct in6_ifaddr *in6_ifaddr;
133 
134 /*
135  * Globals
136  */
137 
138 struct in6_addr zeroin6_addr;
139 
140 extern int ipport_firstauto;
141 extern int ipport_lastauto;
142 extern int ipport_hifirstauto;
143 extern int ipport_hilastauto;
144 
145 /*
146  * Keep separate inet6ctlerrmap, because I may remap some of these.
147  * I also put it here, because, quite frankly, it belongs here, not in
148  * ip{v6,}_input().
149  */
150 #if 0
151 u_char inet6ctlerrmap[PRC_NCMDS] = {
152 	0,		0,		0,		0,
153 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
154 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
155 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
156 	0,		0,		0,		0,
157 	ENOPROTOOPT
158 };
159 #endif
160 
161 /*
162  * Bind an address (or at least a port) to an PF_INET6 socket.
163  */
164 int
165 in6_pcbbind(inp, nam)
166 	struct inpcb *inp;
167 	struct mbuf *nam;
168 {
169 	struct socket *so = inp->inp_socket;
170 
171 	struct inpcbtable *head = inp->inp_table;
172 	struct sockaddr_in6 *sin6;
173 	struct proc *p = curproc;		/* XXX */
174 	u_short lport = 0;
175 	int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT);
176 	int error;
177 
178 	/*
179 	 * REMINDER:  Once up to speed, flow label processing should go here,
180 	 * too.  (Same with in6_pcbconnect.)
181 	 */
182 	if (in6_ifaddr == 0)
183 		return EADDRNOTAVAIL;
184 
185 	if (inp->inp_lport != 0 || !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
186 		return EINVAL;	/* If already bound, EINVAL! */
187 
188 	if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0 &&
189 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
190 	     (so->so_options & SO_ACCEPTCONN) == 0))
191 		wild |= INPLOOKUP_WILDCARD;
192 
193 	/*
194 	 * If I did get a sockaddr passed in...
195 	 */
196 	if (nam) {
197 		sin6 = mtod(nam, struct sockaddr_in6 *);
198 		if (nam->m_len != sizeof (*sin6))
199 			return EINVAL;
200 
201 		/*
202 		 * Unlike v4, I have no qualms about EAFNOSUPPORT if the
203 		 * wretched family is not filled in!
204 		 */
205 		if (sin6->sin6_family != AF_INET6)
206 			return EAFNOSUPPORT;
207 
208 		/* KAME hack: embed scopeid */
209 		if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
210 			return EINVAL;
211 		/* this must be cleared for ifa_ifwithaddr() */
212 		sin6->sin6_scope_id = 0;
213 
214 		lport = sin6->sin6_port;
215 
216 		/* reject IPv4 mapped address, we have no support for it */
217 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
218 			return EADDRNOTAVAIL;
219 
220 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
221 			/*
222 			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
223 			 * allow complete duplication of binding if
224 			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
225 			 * and a multicast address is bound on both
226 			 * new and duplicated sockets.
227 			 */
228 			if (so->so_options & SO_REUSEADDR)
229 				reuseport = SO_REUSEADDR | SO_REUSEPORT;
230 		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
231 			struct ifaddr *ia = NULL;
232 
233 			sin6->sin6_port = 0;  /*
234 					       * Yechhhh, because of upcoming
235 					       * call to ifa_ifwithaddr(), which
236 					       * does bcmp's over the PORTS as
237 					       * well.  (What about flow?)
238 					       */
239 			sin6->sin6_flowinfo = 0;
240 			if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6))
241 			    == NULL)
242 				return EADDRNOTAVAIL;
243 
244 			/*
245 			 * bind to an anycast address might accidentally
246 			 * cause sending a packet with an anycast source
247 			 * address, so we forbid it.
248 			 *
249 			 * We should allow to bind to a deprecated address,
250 			 * since the application dare to use it.
251 			 * But, can we assume that they are careful enough
252 			 * to check if the address is deprecated or not?
253 			 * Maybe, as a safeguard, we should have a setsockopt
254 			 * flag to control the bind(2) behavior against
255 			 * deprecated addresses (default: forbid bind(2)).
256 			 */
257 			if (ia &&
258 			    ((struct in6_ifaddr *)ia)->ia6_flags &
259 			    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
260 				return (EADDRNOTAVAIL);
261 		}
262 		if (lport) {
263 			struct inpcb *t;
264 
265 			/*
266 			 * Question:  Do we wish to continue the Berkeley
267 			 * tradition of ports < IPPORT_RESERVED be only for
268 			 * root?
269 			 * Answer: For now yes, but IMHO, it should be REMOVED!
270 			 * OUCH: One other thing, is there no better way of
271 			 * finding a process for a socket instead of using
272 			 * curproc?  (Marked with BSD's {in,}famous XXX ?
273 			 */
274 			if (ntohs(lport) < IPPORT_RESERVED &&
275 			    (error = suser(p, 0)))
276 				return error;
277 
278 			t = in_pcblookup(head,
279 			    (struct in_addr *)&zeroin6_addr, 0,
280 			    (struct in_addr *)&sin6->sin6_addr, lport,
281 			    wild);
282 
283 			if (t && (reuseport & t->inp_socket->so_options) == 0)
284 				return EADDRINUSE;
285 		}
286 		inp->inp_laddr6 = sin6->sin6_addr;
287 	}
288 
289 	if (lport == 0) {
290 		error = in6_pcbsetport(&inp->inp_laddr6, inp, p);
291 		if (error != 0)
292 			return error;
293 	} else {
294 		inp->inp_lport = lport;
295 		in_pcbrehash(inp);
296 	}
297 
298 	return 0;
299 }
300 
301 int
302 in6_pcbsetport(laddr, inp, p)
303 	struct in6_addr *laddr;
304 	struct inpcb *inp;
305 	struct proc *p;
306 {
307 	struct socket *so = inp->inp_socket;
308 	struct inpcbtable *table = inp->inp_table;
309 	u_int16_t first, last, old = 0;
310 	u_int16_t *lastport = &inp->inp_table->inpt_lastport;
311 	u_int16_t lport = 0;
312 	int count;
313 	int loopcount = 0;
314 	int wild = INPLOOKUP_IPV6;
315 	int error;
316 
317 	/* XXX we no longer support IPv4 mapped address, so no tweaks here */
318 
319 	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
320 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
321 	     (so->so_options & SO_ACCEPTCONN) == 0))
322 		wild |= INPLOOKUP_WILDCARD;
323 
324 	if (inp->inp_flags & INP_HIGHPORT) {
325 		first = ipport_hifirstauto;	/* sysctl */
326 		last = ipport_hilastauto;
327 	} else if (inp->inp_flags & INP_LOWPORT) {
328 		if ((error = suser(p, 0)))
329 			return (EACCES);
330 		first = IPPORT_RESERVED-1; /* 1023 */
331 		last = 600;		   /* not IPPORT_RESERVED/2 */
332 	} else {
333 		first = ipport_firstauto;	/* sysctl */
334 		last  = ipport_lastauto;
335 	}
336 
337 	/*
338 	 * Simple check to ensure all ports are not used up causing
339 	 * a deadlock here.
340 	 *
341 	 * We split the two cases (up and down) so that the direction
342 	 * is not being tested on each round of the loop.
343 	 */
344 
345 portloop:
346 	if (first > last) {
347 		/*
348 		 * counting down
349 		 */
350 		if (loopcount == 0) {	/* only do this once. */
351 			old = first;
352 			first -= (arc4random() % (first - last));
353 		}
354 		count = first - last;
355 		*lastport = first;		/* restart each time */
356 
357 		do {
358 			if (count-- <= 0) {	/* completely used? */
359 				if (loopcount == 0) {
360 					last = old;
361 					loopcount++;
362 					goto portloop;
363 				}
364 				return (EADDRNOTAVAIL);
365 			}
366 			--*lastport;
367 			if (*lastport > first || *lastport < last)
368 				*lastport = first;
369 			lport = htons(*lastport);
370 		} while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
371 		    in_pcblookup(table, &zeroin6_addr, 0,
372 		    &inp->inp_laddr6, lport, wild));
373 	} else {
374 		/*
375 		 * counting up
376 		 */
377 		if (loopcount == 0) {	/* only do this once. */
378 			old = first;
379 			first += (arc4random() % (last - first));
380 		}
381 		count = last - first;
382 		*lastport = first;		/* restart each time */
383 
384 		do {
385 			if (count-- <= 0) {	/* completely used? */
386 				if (loopcount == 0) {
387 					first = old;
388 					loopcount++;
389 					goto portloop;
390 				}
391 				return (EADDRNOTAVAIL);
392 			}
393 			++*lastport;
394 			if (*lastport < first || *lastport > last)
395 				*lastport = first;
396 			lport = htons(*lastport);
397 		} while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
398 		    in_pcblookup(table, &zeroin6_addr, 0,
399 		    &inp->inp_laddr6, lport, wild));
400 	}
401 
402 	inp->inp_lport = lport;
403 	in_pcbrehash(inp);
404 
405 #if 0
406 	inp->inp_flowinfo = 0;	/* XXX */
407 #endif
408 
409 	return 0;
410 }
411 
412 /*
413  * Connect from a socket to a specified address.
414  * Both address and port must be specified in argument sin6.
415  * Eventually, flow labels will have to be dealt with here, as well.
416  *
417  * If don't have a local address for this socket yet,
418  * then pick one.
419  *
420  * I believe this has to be called at splnet().
421  */
422 int
423 in6_pcbconnect(inp, nam)
424 	struct inpcb *inp;
425 	struct mbuf *nam;
426 {
427 	struct in6_addr *in6a = NULL;
428 	struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
429 	struct ifnet *ifp = NULL;	/* outgoing interface */
430 	int error = 0;
431 	struct sockaddr_in6 tmp;
432 
433 	(void)&in6a;				/* XXX fool gcc */
434 
435 	if (nam->m_len != sizeof(*sin6))
436 		return (EINVAL);
437 	if (sin6->sin6_family != AF_INET6)
438 		return (EAFNOSUPPORT);
439 	if (sin6->sin6_port == 0)
440 		return (EADDRNOTAVAIL);
441 
442 	/* reject IPv4 mapped address, we have no support for it */
443 	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
444 		return EADDRNOTAVAIL;
445 
446 	/* sanity check for mapped address case */
447 	if (IN6_IS_ADDR_V4MAPPED(&inp->inp_laddr6))
448 		return EINVAL;
449 
450 	/* protect *sin6 from overwrites */
451 	tmp = *sin6;
452 	sin6 = &tmp;
453 
454 	/* KAME hack: embed scopeid */
455 	if (in6_embedscope(&sin6->sin6_addr, sin6, inp, &ifp) != 0)
456 		return EINVAL;
457 	/* this must be cleared for ifa_ifwithaddr() */
458 	sin6->sin6_scope_id = 0;
459 
460 	/* Source address selection. */
461 	/*
462 	 * XXX: in6_selectsrc might replace the bound local address
463 	 * with the address specified by setsockopt(IPV6_PKTINFO).
464 	 * Is it the intended behavior?
465 	 */
466 	in6a = in6_selectsrc(sin6, inp->inp_outputopts6,
467 	    inp->inp_moptions6, &inp->inp_route6, &inp->inp_laddr6,
468 	    &error);
469 	if (in6a == 0) {
470 		if (error == 0)
471 			error = EADDRNOTAVAIL;
472 		return (error);
473 	}
474 
475 	if (inp->inp_route6.ro_rt)
476 		ifp = inp->inp_route6.ro_rt->rt_ifp;
477 
478 	inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp, ifp);
479 
480 	if (in_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
481 	    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6,
482 	    inp->inp_lport, INPLOOKUP_IPV6)) {
483 		return (EADDRINUSE);
484 	}
485 	if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
486 		if (inp->inp_lport == 0)
487 			(void)in6_pcbbind(inp, (struct mbuf *)0);
488 		inp->inp_laddr6 = *in6a;
489 	}
490 	inp->inp_faddr6 = sin6->sin6_addr;
491 	inp->inp_fport = sin6->sin6_port;
492 	inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK;
493 	if (ip6_auto_flowlabel)
494 		inp->inp_flowinfo |=
495 		    (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
496 	in_pcbrehash(inp);
497 	return (0);
498 }
499 
500 /*
501  * Pass some notification to all connections of a protocol
502  * associated with address dst.  The local address and/or port numbers
503  * may be specified to limit the search.  The "usual action" will be
504  * taken, depending on the ctlinput cmd.  The caller must filter any
505  * cmds that are uninteresting (e.g., no error in the map).
506  * Call the protocol specific routine (if any) to report
507  * any errors for each matching socket.
508  *
509  * Also perform input-side security policy check
510  *    once PCB to be notified has been located.
511  *
512  * Must be called at splnet.
513  */
514 int
515 in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
516 	struct inpcbtable *head;
517 	struct sockaddr *dst, *src;
518 	uint fport_arg;
519 	uint lport_arg;
520 	int cmd;
521 	void *cmdarg;
522 	void (*notify)(struct inpcb *, int);
523 {
524 	struct inpcb *inp, *ninp;
525 	u_short fport = fport_arg, lport = lport_arg;
526 	struct sockaddr_in6 sa6_src, *sa6_dst;
527 	int errno, nmatch = 0;
528 	u_int32_t flowinfo;
529 
530 	if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6)
531 		return (0);
532 
533 	sa6_dst = (struct sockaddr_in6 *)dst;
534 	if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
535 		return (0);
536 	if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr)) {
537 #ifdef DIAGNOSTIC
538 		printf("Huh?  Thought in6_pcbnotify() never got "
539 		       "called with mapped!\n");
540 #endif
541 		return (0);
542 	}
543 
544 	/*
545 	 * note that src can be NULL when we get notify by local fragmentation.
546 	 */
547 	sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
548 	flowinfo = sa6_src.sin6_flowinfo;
549 
550 	/*
551 	 * Redirects go to all references to the destination,
552 	 * and use in_rtchange to invalidate the route cache.
553 	 * Dead host indications: also use in_rtchange to invalidate
554 	 * the cache, and deliver the error to all the sockets.
555 	 * Otherwise, if we have knowledge of the local port and address,
556 	 * deliver only to that socket.
557 	 */
558 	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
559 		fport = 0;
560 		lport = 0;
561 		sa6_src.sin6_addr = in6addr_any;
562 
563 		if (cmd != PRC_HOSTDEAD)
564 			notify = in_rtchange;
565 	}
566 	errno = inet6ctlerrmap[cmd];
567 
568 	for (inp = CIRCLEQ_FIRST(&head->inpt_queue);
569 	     inp != CIRCLEQ_END(&head->inpt_queue); inp = ninp) {
570 		ninp = CIRCLEQ_NEXT(inp, inp_queue);
571 
572 		if ((inp->inp_flags & INP_IPV6) == 0)
573 			continue;
574 
575 		/*
576 		 * Under the following condition, notify of redirects
577 		 * to the pcb, without making address matches against inpcb.
578 		 * - redirect notification is arrived.
579 		 * - the inpcb is unconnected.
580 		 * - the inpcb is caching !RTF_HOST routing entry.
581 		 * - the ICMPv6 notification is from the gateway cached in the
582 		 *   inpcb.  i.e. ICMPv6 notification is from nexthop gateway
583 		 *   the inpcb used very recently.
584 		 *
585 		 * This is to improve interaction between netbsd/openbsd
586 		 * redirect handling code, and inpcb route cache code.
587 		 * without the clause, !RTF_HOST routing entry (which carries
588 		 * gateway used by inpcb right before the ICMPv6 redirect)
589 		 * will be cached forever in unconnected inpcb.
590 		 *
591 		 * There still is a question regarding to what is TRT:
592 		 * - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
593 		 *   generated on packet output.  inpcb will always cache
594 		 *   RTF_HOST routing entry so there's no need for the clause
595 		 *   (ICMPv6 redirect will update RTF_HOST routing entry,
596 		 *   and inpcb is caching it already).
597 		 *   However, bsdi/freebsd are vulnerable to local DoS attacks
598 		 *   due to the cloned routing entries.
599 		 * - Specwise, "destination cache" is mentioned in RFC2461.
600 		 *   Jinmei says that it implies bsdi/freebsd behavior, itojun
601 		 *   is not really convinced.
602 		 * - Having hiwat/lowat on # of cloned host route (redirect/
603 		 *   pmtud) may be a good idea.  netbsd/openbsd has it.  see
604 		 *   icmp6_mtudisc_update().
605 		 */
606 		if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
607 		    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
608 		    inp->inp_route.ro_rt &&
609 		    !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
610 			struct sockaddr_in6 *dst6;
611 
612 			dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst;
613 			if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
614 			    &sa6_dst->sin6_addr))
615 				goto do_notify;
616 		}
617 
618 		/*
619 		 * Detect if we should notify the error. If no source and
620 		 * destination ports are specified, but non-zero flowinfo and
621 		 * local address match, notify the error. This is the case
622 		 * when the error is delivered with an encrypted buffer
623 		 * by ESP. Otherwise, just compare addresses and ports
624 		 * as usual.
625 		 */
626 		if (lport == 0 && fport == 0 && flowinfo &&
627 		    inp->inp_socket != NULL &&
628 		    flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
629 		    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
630 			goto do_notify;
631 		else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
632 					     &sa6_dst->sin6_addr) ||
633 			 inp->inp_socket == 0 ||
634 			 (lport && inp->inp_lport != lport) ||
635 			 (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
636 			  !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
637 					      &sa6_src.sin6_addr)) ||
638 			 (fport && inp->inp_fport != fport)) {
639 			continue;
640 		}
641 	  do_notify:
642 		nmatch++;
643 		if (notify)
644 			(*notify)(inp, errno);
645 	}
646 	return (nmatch);
647 }
648 
649 /*
650  * Get the local address/port, and put it in a sockaddr_in6.
651  * This services the getsockname(2) call.
652  */
653 int
654 in6_setsockaddr(inp, nam)
655 	struct inpcb *inp;
656 	struct mbuf *nam;
657 {
658 	struct sockaddr_in6 *sin6;
659 
660 	nam->m_len = sizeof(struct sockaddr_in6);
661 	sin6 = mtod(nam,struct sockaddr_in6 *);
662 
663 	bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
664 	sin6->sin6_family = AF_INET6;
665 	sin6->sin6_len = sizeof(struct sockaddr_in6);
666 	sin6->sin6_port = inp->inp_lport;
667 	sin6->sin6_addr = inp->inp_laddr6;
668 	/* KAME hack: recover scopeid */
669 	(void)in6_recoverscope(sin6, &inp->inp_laddr6, NULL);
670 
671 	return 0;
672 }
673 
674 /*
675  * Get the foreign address/port, and put it in a sockaddr_in6.
676  * This services the getpeername(2) call.
677  */
678 int
679 in6_setpeeraddr(inp, nam)
680 	struct inpcb *inp;
681 	struct mbuf *nam;
682 {
683 	struct sockaddr_in6 *sin6;
684 
685 	nam->m_len = sizeof(struct sockaddr_in6);
686 	sin6 = mtod(nam,struct sockaddr_in6 *);
687 
688 	bzero ((caddr_t)sin6,sizeof(struct sockaddr_in6));
689 	sin6->sin6_family = AF_INET6;
690 	sin6->sin6_len = sizeof(struct sockaddr_in6);
691 	sin6->sin6_port = inp->inp_fport;
692 	sin6->sin6_addr = inp->inp_faddr6;
693 	/* KAME hack: recover scopeid */
694 	(void)in6_recoverscope(sin6, &inp->inp_faddr6, NULL);
695 
696 	return 0;
697 }
698