xref: /netbsd-src/sys/netinet6/in6_pcb.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: in6_pcb.c,v 1.29 2000/07/07 15:54:18 itojun Exp $	*/
2 /*	$KAME: in6_pcb.c,v 1.57 2000/07/07 10:27:12 itojun Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1982, 1986, 1991, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. All advertising materials mentioning features or use of this software
46  *    must display the following acknowledgement:
47  *	This product includes software developed by the University of
48  *	California, Berkeley and its contributors.
49  * 4. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94
66  */
67 
68 #include "opt_ipsec.h"
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/malloc.h>
73 #include <sys/mbuf.h>
74 #include <sys/protosw.h>
75 #include <sys/socket.h>
76 #include <sys/socketvar.h>
77 #include <sys/ioctl.h>
78 #include <sys/errno.h>
79 #include <sys/time.h>
80 #include <sys/proc.h>
81 
82 #include <net/if.h>
83 #include <net/route.h>
84 
85 #include <netinet/in.h>
86 #include <netinet/in_var.h>
87 #include <netinet/in_systm.h>
88 #include <netinet/ip.h>
89 #include <netinet/in_pcb.h>
90 #include <netinet/ip6.h>
91 #include <netinet6/ip6_var.h>
92 #include <netinet6/in6_pcb.h>
93 #include <netinet6/nd6.h>
94 
95 #include "loop.h"
96 extern struct ifnet loif[NLOOP];
97 #include "faith.h"
98 
99 #ifdef IPSEC
100 #include <netinet6/ipsec.h>
101 #include <netkey/key.h>
102 #endif /* IPSEC */
103 
104 struct in6_addr zeroin6_addr;
105 
106 int
107 in6_pcballoc(so, head)
108 	struct socket *so;
109 	struct in6pcb *head;
110 {
111 	struct in6pcb *in6p;
112 
113 	MALLOC(in6p, struct in6pcb *, sizeof(*in6p), M_PCB, M_NOWAIT);
114 	if (in6p == NULL)
115 		return(ENOBUFS);
116 	bzero((caddr_t)in6p, sizeof(*in6p));
117 	in6p->in6p_head = head;
118 	in6p->in6p_socket = so;
119 	in6p->in6p_hops = -1;	/* use kernel default */
120 	in6p->in6p_icmp6filt = NULL;
121 	in6p->in6p_next = head->in6p_next;
122 	head->in6p_next = in6p;
123 	in6p->in6p_prev = head;
124 	in6p->in6p_next->in6p_prev = in6p;
125 #ifndef INET6_BINDV6ONLY
126 	if (ip6_bindv6only)
127 		in6p->in6p_flags |= IN6P_BINDV6ONLY;
128 #else
129 	in6p->in6p_flags |= IN6P_BINDV6ONLY;	/*just for safety*/
130 #endif
131 	so->so_pcb = (caddr_t)in6p;
132 	return(0);
133 }
134 
135 int
136 in6_pcbbind(in6p, nam, p)
137 	register struct in6pcb *in6p;
138 	struct mbuf *nam;
139 	struct proc *p;
140 {
141 	struct socket *so = in6p->in6p_socket;
142 	struct in6pcb *head = in6p->in6p_head;
143 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
144 	u_int16_t lport = 0;
145 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
146 
147 	if (in6p->in6p_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
148 		return(EINVAL);
149 	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
150 	   ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
151 	    (so->so_options & SO_ACCEPTCONN) == 0))
152 		wild = IN6PLOOKUP_WILDCARD;
153 	if (nam) {
154 		sin6 = mtod(nam, struct sockaddr_in6 *);
155 		if (nam->m_len != sizeof(*sin6))
156 			return(EINVAL);
157 		/*
158 		 * We should check the family, but old programs
159 		 * incorrectly fail to intialize it.
160 		 */
161 		if (sin6->sin6_family != AF_INET6)
162 			return(EAFNOSUPPORT);
163 
164 		/*
165 		 * since we do not check port number duplicate with IPv4 space,
166 		 * we reject it at this moment.  If we leave it, we make normal
167 		 * user to hijack port number from other users.
168 		 */
169 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
170 			return(EADDRNOTAVAIL);
171 
172 		/* KAME hack: embed scopeid */
173 		if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0)
174 			return EINVAL;
175 		/* this must be cleared for ifa_ifwithaddr() */
176 		sin6->sin6_scope_id = 0;
177 
178 		lport = sin6->sin6_port;
179 		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
180 			/*
181 			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
182 			 * allow compepte duplication of binding if
183 			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
184 			 * and a multicast address is bound on both
185 			 * new and duplicated sockets.
186 			 */
187 			if (so->so_options & SO_REUSEADDR)
188 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
189 		} else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
190 			struct sockaddr_in sin;
191 
192 			bzero(&sin, sizeof(sin));
193 			sin.sin_len = sizeof(sin);
194 			sin.sin_family = AF_INET;
195 			bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
196 				sizeof(sin.sin_addr));
197 			if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0)
198 				return EADDRNOTAVAIL;
199 		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
200 			struct ifaddr *ia = NULL;
201 
202 			sin6->sin6_port = 0;		/* yech... */
203 #if defined(NFAITH) && NFAITH > 0
204 			if ((in6p->in6p_flags & IN6P_FAITH) == 0
205 			 && (ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
206 #else
207 			if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0)
208 #endif
209 				return(EADDRNOTAVAIL);
210 
211 			/*
212 			 * XXX: bind to an anycast address might accidentally
213 			 * cause sending a packet with anycast source address.
214 			 */
215 			if (ia &&
216 			    ((struct in6_ifaddr *)ia)->ia6_flags &
217 			    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
218 			     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
219 				return(EADDRNOTAVAIL);
220 			}
221 		}
222 		if (lport) {
223 #ifndef IPNOPRIVPORTS
224 			int priv;
225 
226 			/*
227 			 * NOTE: all operating systems use suser() for
228 			 * privilege check!  do not rewrite it into SS_PRIV.
229 			 */
230 			priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
231 			/* GROSS */
232 			if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
233 				return(EACCES);
234 #endif
235 
236 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
237 				/* should check this but we can't ... */
238 #if 0
239 				struct inpcb *t;
240 
241 				t = in_pcblookup_bind(&tcbtable,
242 					(struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
243 					lport);
244 				if (t && (reuseport & t->inp_socket->so_options) == 0)
245 					return EADDRINUSE;
246 #endif
247 			} else {
248 				struct in6pcb *t;
249 
250 				t = in6_pcblookup(head, &zeroin6_addr, 0,
251 						  &sin6->sin6_addr, lport, wild);
252 				if (t && (reuseport & t->in6p_socket->so_options) == 0)
253 					return(EADDRINUSE);
254 			}
255 		}
256 		in6p->in6p_laddr = sin6->sin6_addr;
257 	}
258 
259 	if (lport == 0) {
260 		int e;
261 		if ((e = in6_pcbsetport(&in6p->in6p_laddr, in6p)) != 0)
262 			return(e);
263 	}
264 	else
265 		in6p->in6p_lport = lport;
266 
267 	in6p->in6p_flowinfo = sin6 ? sin6->sin6_flowinfo : 0;	/*XXX*/
268 	return(0);
269 }
270 
271 /*
272  * Connect from a socket to a specified address.
273  * Both address and port must be specified in argument sin6.
274  * If don't have a local address for this socket yet,
275  * then pick one.
276  */
277 int
278 in6_pcbconnect(in6p, nam)
279 	struct in6pcb *in6p;
280 	struct mbuf *nam;
281 {
282 	struct in6_addr *in6a = NULL;
283 	struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
284 	struct ifnet *ifp = NULL;	/* outgoing interface */
285 	int error = 0;
286 	struct in6_addr mapped;
287 	struct sockaddr_in6 tmp;
288 
289 	(void)&in6a;				/* XXX fool gcc */
290 
291 	if (nam->m_len != sizeof(*sin6))
292 		return(EINVAL);
293 	if (sin6->sin6_family != AF_INET6)
294 		return(EAFNOSUPPORT);
295 	if (sin6->sin6_port == 0)
296 		return(EADDRNOTAVAIL);
297 
298 	/* sanity check for mapped address case */
299 	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
300 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
301 			in6p->in6p_laddr.s6_addr16[5] = htons(0xffff);
302 		if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
303 			return EINVAL;
304 	} else {
305 		if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
306 			return EINVAL;
307 	}
308 
309 	/* protect *sin6 from overwrites */
310 	tmp = *sin6;
311 	sin6 = &tmp;
312 
313 	/* KAME hack: embed scopeid */
314 	if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, &ifp) != 0)
315 		return EINVAL;
316 
317 	/* Source address selection. */
318 	if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
319 	 && in6p->in6p_laddr.s6_addr32[3] == 0) {
320 		struct sockaddr_in sin, *sinp;
321 
322 		bzero(&sin, sizeof(sin));
323 		sin.sin_len = sizeof(sin);
324 		sin.sin_family = AF_INET;
325 		bcopy(&sin6->sin6_addr.s6_addr32[3], &sin.sin_addr,
326 			sizeof(sin.sin_addr));
327 		sinp = in_selectsrc(&sin, (struct route *)&in6p->in6p_route,
328 			in6p->in6p_socket->so_options, NULL, &error);
329 		if (sinp == 0) {
330 			if (error == 0)
331 				error = EADDRNOTAVAIL;
332 			return(error);
333 		}
334 		bzero(&mapped, sizeof(mapped));
335 		mapped.s6_addr16[5] = htons(0xffff);
336 		bcopy(&sinp->sin_addr, &mapped.s6_addr32[3], sizeof(sinp->sin_addr));
337 		in6a = &mapped;
338 	} else {
339 		/*
340 		 * XXX: in6_selectsrc might replace the bound local address
341 		 * with the address specified by setsockopt(IPV6_PKTINFO).
342 		 * Is it the intended behavior?
343 		 */
344 		in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
345 				     in6p->in6p_moptions,
346 				     &in6p->in6p_route,
347 				     &in6p->in6p_laddr, &error);
348 		if (in6a == 0) {
349 			if (error == 0)
350 				error = EADDRNOTAVAIL;
351 			return(error);
352 		}
353 	}
354 	if (in6p->in6p_route.ro_rt)
355 		ifp = in6p->in6p_route.ro_rt->rt_ifp;
356 
357 	in6p->in6p_ip6.ip6_hlim = (u_int8_t)in6_selecthlim(in6p, ifp);
358 
359 	if (in6_pcblookup(in6p->in6p_head,
360 			 &sin6->sin6_addr,
361 			 sin6->sin6_port,
362 			 IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) ?
363 			  in6a : &in6p->in6p_laddr,
364 			 in6p->in6p_lport,
365 			 0))
366 		return(EADDRINUSE);
367 	if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)
368 	 || (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
369 	  && in6p->in6p_laddr.s6_addr32[3] == 0)) {
370 		if (in6p->in6p_lport == 0) {
371 #ifdef __NetBSD__
372 			(void)in6_pcbbind(in6p, (struct mbuf *)0,
373 			    (struct proc *)0);
374 #else
375 			(void)in6_pcbbind(in6p, (struct mbuf *)0);
376 #endif
377 		}
378 		in6p->in6p_laddr = *in6a;
379 	}
380 	in6p->in6p_faddr = sin6->sin6_addr;
381 	in6p->in6p_fport = sin6->sin6_port;
382 	/*
383 	 * xxx kazu flowlabel is necessary for connect?
384 	 * but if this line is missing, the garbage value remains.
385 	 */
386 	in6p->in6p_flowinfo = sin6->sin6_flowinfo;
387 	return(0);
388 }
389 
390 void
391 in6_pcbdisconnect(in6p)
392 	struct in6pcb *in6p;
393 {
394 	bzero((caddr_t)&in6p->in6p_faddr, sizeof(in6p->in6p_faddr));
395 	in6p->in6p_fport = 0;
396 	if (in6p->in6p_socket->so_state & SS_NOFDREF)
397 		in6_pcbdetach(in6p);
398 }
399 
400 void
401 in6_pcbdetach(in6p)
402 	struct in6pcb *in6p;
403 {
404 	struct socket *so = in6p->in6p_socket;
405 
406 #ifdef IPSEC
407 	ipsec6_delete_pcbpolicy(in6p);
408 #endif /* IPSEC */
409 	sotoin6pcb(so) = 0;
410 	sofree(so);
411 	if (in6p->in6p_options)
412 		m_freem(in6p->in6p_options);
413 	if (in6p->in6p_outputopts) {
414 		if (in6p->in6p_outputopts->ip6po_rthdr &&
415 		    in6p->in6p_outputopts->ip6po_route.ro_rt)
416 			RTFREE(in6p->in6p_outputopts->ip6po_route.ro_rt);
417 		if (in6p->in6p_outputopts->ip6po_m)
418 			(void)m_free(in6p->in6p_outputopts->ip6po_m);
419 		free(in6p->in6p_outputopts, M_IP6OPT);
420 	}
421 	if (in6p->in6p_route.ro_rt)
422 		rtfree(in6p->in6p_route.ro_rt);
423 	ip6_freemoptions(in6p->in6p_moptions);
424 	in6p->in6p_next->in6p_prev = in6p->in6p_prev;
425 	in6p->in6p_prev->in6p_next = in6p->in6p_next;
426 	in6p->in6p_prev = NULL;
427 	FREE(in6p, M_PCB);
428 }
429 
430 void
431 in6_setsockaddr(in6p, nam)
432 	struct in6pcb *in6p;
433 	struct mbuf *nam;
434 {
435 	struct sockaddr_in6 *sin6;
436 
437 	nam->m_len = sizeof(*sin6);
438 	sin6 = mtod(nam, struct sockaddr_in6 *);
439 	bzero((caddr_t)sin6, sizeof(*sin6));
440 	sin6->sin6_family = AF_INET6;
441 	sin6->sin6_len = sizeof(struct sockaddr_in6);
442 	sin6->sin6_port = in6p->in6p_lport;
443 	/* KAME hack: recover scopeid */
444 	(void)in6_recoverscope(sin6, &in6p->in6p_laddr, NULL);
445 }
446 
447 void
448 in6_setpeeraddr(in6p, nam)
449 	struct in6pcb *in6p;
450 	struct mbuf *nam;
451 {
452 	struct sockaddr_in6 *sin6;
453 
454 	nam->m_len = sizeof(*sin6);
455 	sin6 = mtod(nam, struct sockaddr_in6 *);
456 	bzero((caddr_t)sin6, sizeof(*sin6));
457 	sin6->sin6_family = AF_INET6;
458 	sin6->sin6_len = sizeof(struct sockaddr_in6);
459 	sin6->sin6_port = in6p->in6p_fport;
460 	/* KAME hack: recover scopeid */
461 	(void)in6_recoverscope(sin6, &in6p->in6p_faddr, NULL);
462 }
463 
464 /*
465  * Pass some notification to all connections of a protocol
466  * associated with address dst.  The local address and/or port numbers
467  * may be specified to limit the search.  The "usual action" will be
468  * taken, depending on the ctlinput cmd.  The caller must filter any
469  * cmds that are uninteresting (e.g., no error in the map).
470  * Call the protocol specific routine (if any) to report
471  * any errors for each matching socket.
472  *
473  * Must be called at splsoftnet.
474  */
475 int
476 in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
477 	struct in6pcb *head;
478 	struct sockaddr *dst;
479 	u_int fport_arg, lport_arg;
480 	struct in6_addr *laddr6;
481 	int cmd;
482 	void (*notify) __P((struct in6pcb *, int));
483 {
484 	struct in6pcb *in6p, *nin6p;
485 	struct in6_addr faddr6;
486 	u_int16_t fport = fport_arg, lport = lport_arg;
487 	int errno;
488 	int nmatch = 0;
489 	int do_rtchange = (notify == in6_rtchange);
490 
491 	if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
492 		return 0;
493 	faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
494 	if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
495 		return 0;
496 
497 	/*
498 	 * Redirects go to all references to the destination,
499 	 * and use in6_rtchange to invalidate the route cache.
500 	 * Dead host indications: also use in6_rtchange to invalidate
501 	 * the cache, and deliver the error to all the sockets.
502 	 * Otherwise, if we have knowledge of the local port and address,
503 	 * deliver only to that socket.
504 	 */
505 	if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
506 		fport = 0;
507 		lport = 0;
508 		bzero((caddr_t)laddr6, sizeof(*laddr6));
509 
510 		do_rtchange = 1;
511 	}
512 
513 	if (notify == NULL)
514 		return 0;
515 
516 	errno = inet6ctlerrmap[cmd];
517 	for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
518 		nin6p = in6p->in6p_next;
519 
520 		if (do_rtchange) {
521 			/*
522 			 * Since a non-connected PCB might have a cached route,
523 			 * we always call in6_rtchange without matching
524 			 * the PCB to the src/dst pair.
525 			 *
526 			 * XXX: we assume in6_rtchange does not free the PCB.
527 			 */
528 			if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_route.ro_dst.sin6_addr,
529 					       &faddr6))
530 				in6_rtchange(in6p, errno);
531 
532 			if (notify == in6_rtchange)
533 				continue; /* there's nothing to do any more */
534 		}
535 
536 		/* at this point, we can assume that NOTIFY is not NULL. */
537 
538 		if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &faddr6) ||
539 		    in6p->in6p_socket == 0 ||
540 		    (lport && in6p->in6p_lport != lport) ||
541 		    (!IN6_IS_ADDR_UNSPECIFIED(laddr6) &&
542 		     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) ||
543 		    (fport && in6p->in6p_fport != fport))
544 			continue;
545 
546 		(*notify)(in6p, errno);
547 		nmatch++;
548 	}
549 	return nmatch;
550 }
551 
552 void
553 in6_pcbpurgeif(head, ifp)
554 	struct in6pcb *head;
555 	struct ifnet *ifp;
556 {
557 	struct in6pcb *in6p, *nin6p;
558 
559 	for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
560 		nin6p = in6p->in6p_next;
561 		if (in6p->in6p_route.ro_rt != NULL &&
562 		    in6p->in6p_route.ro_rt->rt_ifp == ifp)
563 			in6_rtchange(in6p, 0);
564 	}
565 }
566 
567 /*
568  * Check for alternatives when higher level complains
569  * about service problems.  For now, invalidate cached
570  * routing information.  If the route was created dynamically
571  * (by a redirect), time to try a default gateway again.
572  */
573 void
574 in6_losing(in6p)
575 	struct in6pcb *in6p;
576 {
577 	struct rtentry *rt;
578 	struct rt_addrinfo info;
579 
580 	if ((rt = in6p->in6p_route.ro_rt) != NULL) {
581 		in6p->in6p_route.ro_rt = 0;
582 		bzero((caddr_t)&info, sizeof(info));
583 		info.rti_info[RTAX_DST] =
584 			(struct sockaddr *)&in6p->in6p_route.ro_dst;
585 		info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
586 		info.rti_info[RTAX_NETMASK] = rt_mask(rt);
587 		rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
588 		if (rt->rt_flags & RTF_DYNAMIC)
589 			(void)rtrequest(RTM_DELETE, rt_key(rt),
590 					rt->rt_gateway, rt_mask(rt), rt->rt_flags,
591 					(struct rtentry **)0);
592 		else
593 		/*
594 		 * A new route can be allocated
595 		 * the next time output is attempted.
596 		 */
597 			rtfree(rt);
598 	}
599 }
600 
601 /*
602  * After a routing change, flush old routing
603  * and allocate a (hopefully) better one.
604  */
605 void
606 in6_rtchange(in6p, errno)
607 	struct in6pcb *in6p;
608 	int errno;
609 {
610 	if (in6p->in6p_route.ro_rt) {
611 		rtfree(in6p->in6p_route.ro_rt);
612 		in6p->in6p_route.ro_rt = 0;
613 		/*
614 		 * A new route can be allocated the next time
615 		 * output is attempted.
616 		 */
617 	}
618 }
619 
620 struct in6pcb *
621 in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags)
622 	struct in6pcb *head;
623 	struct in6_addr *faddr6, *laddr6;
624 	u_int fport_arg, lport_arg;
625 	int flags;
626 {
627 	struct in6pcb *in6p, *match = 0;
628 	int matchwild = 3, wildcard;
629 	u_int16_t fport = fport_arg, lport = lport_arg;
630 
631 	for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
632 		if (in6p->in6p_lport != lport)
633 			continue;
634 		wildcard = 0;
635 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
636 			if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
637 				wildcard++;
638 			else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
639 				continue;
640 		}
641 #ifndef TCP6
642 		else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
643 			&& in6p->in6p_laddr.s6_addr32[3] == 0) {
644 			if (!IN6_IS_ADDR_V4MAPPED(laddr6))
645 				continue;
646 			if (laddr6->s6_addr32[3] == 0)
647 				;
648 			else
649 				wildcard++;
650 		}
651 #endif
652 		else {
653 			if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
654 #if !defined(TCP6) && !defined(INET6_BINDV6ONLY)
655 				if (in6p->in6p_flags & IN6P_BINDV6ONLY)
656 					continue;
657 				else
658 					wildcard++;
659 #else
660 				continue;
661 #endif
662 			} else if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
663 				wildcard++;
664 		}
665 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
666 			if (IN6_IS_ADDR_UNSPECIFIED(faddr6))
667 				wildcard++;
668 			else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6)
669 			      || in6p->in6p_fport != fport)
670 				continue;
671 		}
672 #ifndef TCP6
673 		else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)
674 			&& in6p->in6p_faddr.s6_addr32[3] == 0) {
675 			if (!IN6_IS_ADDR_V4MAPPED(faddr6))
676 				continue;
677 			if (faddr6->s6_addr32[3] == 0)
678 				;
679 			else
680 				wildcard++;
681 		}
682 #endif
683 		else {
684 			if (IN6_IS_ADDR_V4MAPPED(faddr6)) {
685 #if !defined(TCP6) && !defined(INET6_BINDV6ONLY)
686 				if (in6p->in6p_flags & IN6P_BINDV6ONLY)
687 					continue;
688 				else
689 					wildcard++;
690 #else
691 				continue;
692 #endif
693 			} else if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
694 				wildcard++;
695 		}
696 
697 		if (wildcard && (flags & IN6PLOOKUP_WILDCARD) == 0)
698 			continue;
699 		if (wildcard < matchwild) {
700 			match = in6p;
701 			matchwild = wildcard;
702 			if (matchwild == 0)
703 				break;
704 		}
705 	}
706 	return(match);
707 }
708 
709 #ifndef TCP6
710 struct rtentry *
711 in6_pcbrtentry(in6p)
712 	struct in6pcb *in6p;
713 {
714 	struct route_in6 *ro;
715 
716 	ro = &in6p->in6p_route;
717 
718 	if (ro->ro_rt == NULL) {
719 		/*
720 		 * No route yet, so try to acquire one.
721 		 */
722 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
723 			bzero(&ro->ro_dst, sizeof(ro->ro_dst));
724 			ro->ro_dst.sin6_family = AF_INET6;
725 			ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
726 			satosin6(&ro->ro_dst)->sin6_addr = in6p->in6p_faddr;
727 			rtalloc((struct route *)ro);
728 		}
729 	}
730 	return (ro->ro_rt);
731 }
732 
733 struct in6pcb *
734 in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg, faith)
735 	struct in6pcb *head;
736 	struct in6_addr *faddr6, *laddr6;
737 	u_int fport_arg, lport_arg;
738 	int faith;
739 {
740 	struct in6pcb *in6p;
741 	u_int16_t fport = fport_arg, lport = lport_arg;
742 
743 	for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
744 		/* find exact match on both source and dest */
745 		if (in6p->in6p_fport != fport)
746 			continue;
747 		if (in6p->in6p_lport != lport)
748 			continue;
749 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
750 			continue;
751 		if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, faddr6))
752 			continue;
753 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
754 			continue;
755 		if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
756 			continue;
757 		return in6p;
758 	}
759 	return NULL;
760 }
761 
762 struct in6pcb *
763 in6_pcblookup_bind(head, laddr6, lport_arg, faith)
764 	struct in6pcb *head;
765 	struct in6_addr *laddr6;
766 	u_int lport_arg;
767 	int faith;
768 {
769 	struct in6pcb *in6p, *match;
770 	u_int16_t lport = lport_arg;
771 
772 	match = NULL;
773 	for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
774 		/*
775 	 	 * find destination match.  exact match is preferred
776 		 * against wildcard match.
777 		 */
778 #if defined(NFAITH) && NFAITH > 0
779 		if (faith && (in6p->in6p_flags & IN6P_FAITH) == 0)
780 			continue;
781 #endif
782 		if (in6p->in6p_fport != 0)
783 			continue;
784 		if (in6p->in6p_lport != lport)
785 			continue;
786 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
787 			if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
788 #ifndef INET6_BINDV6ONLY
789 				if (in6p->in6p_flags & IN6P_BINDV6ONLY)
790 					continue;
791 				else
792 					match = in6p;
793 #else
794 				continue;
795 #endif
796 			} else
797 				match = in6p;
798 		}
799 		else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
800 			 in6p->in6p_laddr.s6_addr32[3] == 0) {
801 			if (IN6_IS_ADDR_V4MAPPED(laddr6) &&
802 			    laddr6->s6_addr32[3] != 0)
803 				match = in6p;
804 		}
805 		else if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
806 			return in6p;
807 	}
808 	return match;
809 }
810 #endif
811