Home | History | Annotate | Line # | Download | only in netinet6
raw_ip6.c revision 1.14
      1 /*	$NetBSD: raw_ip6.c,v 1.14 1999/12/22 04:03:04 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1982, 1986, 1988, 1993
     34  *	The Regents of the University of California.  All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed by the University of
     47  *	California, Berkeley and its contributors.
     48  * 4. Neither the name of the University nor the names of its contributors
     49  *    may be used to endorse or promote products derived from this software
     50  *    without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  * SUCH DAMAGE.
     63  *
     64  *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
     65  */
     66 
     67 #ifdef __NetBSD__	/*XXX*/
     68 #include "opt_ipsec.h"
     69 #endif
     70 
     71 #include <sys/param.h>
     72 #include <sys/malloc.h>
     73 #include <sys/mbuf.h>
     74 #include <sys/socket.h>
     75 #include <sys/protosw.h>
     76 #include <sys/socketvar.h>
     77 #include <sys/errno.h>
     78 #include <sys/systm.h>
     79 #ifdef __NetBSD__
     80 #include <sys/proc.h>
     81 #endif
     82 
     83 #include <net/if.h>
     84 #include <net/route.h>
     85 #include <net/if_types.h>
     86 
     87 #include <netinet/in.h>
     88 #include <netinet/in_var.h>
     89 #include <netinet6/ip6.h>
     90 #include <netinet6/ip6_var.h>
     91 #include <netinet6/ip6_mroute.h>
     92 #include <netinet6/icmp6.h>
     93 #include <netinet6/in6_pcb.h>
     94 #include <netinet6/nd6.h>
     95 
     96 #ifdef IPSEC
     97 #include <netinet6/ipsec.h>
     98 #endif /*IPSEC*/
     99 
    100 #include <machine/stdarg.h>
    101 
    102 #include "faith.h"
    103 
    104 struct	in6pcb rawin6pcb;
    105 #define ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
    106 
    107 /*
    108  * Raw interface to IP6 protocol.
    109  */
    110 
    111 /*
    112  * Initialize raw connection block queue.
    113  */
    114 void
    115 rip6_init()
    116 {
    117 	rawin6pcb.in6p_next = rawin6pcb.in6p_prev = &rawin6pcb;
    118 }
    119 
    120 /*
    121  * Setup generic address and protocol structures
    122  * for raw_input routine, then pass them along with
    123  * mbuf chain.
    124  */
    125 int
    126 rip6_input(mp, offp, proto)
    127 	struct	mbuf **mp;
    128 	int	*offp, proto;
    129 {
    130 	struct mbuf *m = *mp;
    131 	register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
    132 	register struct in6pcb *in6p;
    133 	struct in6pcb *last = NULL;
    134 	struct sockaddr_in6 rip6src;
    135 	struct mbuf *opts = NULL;
    136 
    137 #if defined(NFAITH) && 0 < NFAITH
    138 	if (m->m_pkthdr.rcvif) {
    139 		if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
    140 			/* send icmp6 host unreach? */
    141 			m_freem(m);
    142 			return IPPROTO_DONE;
    143 		}
    144 	}
    145 #endif
    146 
    147 	/* Be proactive about malicious use of IPv4 mapped address */
    148 	if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
    149 	    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
    150 		/* XXX stat */
    151 		m_freem(m);
    152 		return IPPROTO_DONE;
    153 	}
    154 
    155 	bzero(&rip6src, sizeof(rip6src));
    156 	rip6src.sin6_len = sizeof(struct sockaddr_in6);
    157 	rip6src.sin6_family = AF_INET6;
    158 	rip6src.sin6_addr = ip6->ip6_src;
    159 	if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
    160 		rip6src.sin6_addr.s6_addr16[1] = 0;
    161 	if (m->m_pkthdr.rcvif) {
    162 		if (IN6_IS_SCOPE_LINKLOCAL(&rip6src.sin6_addr))
    163 			rip6src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
    164 		else
    165 			rip6src.sin6_scope_id = 0;
    166 	} else
    167 		rip6src.sin6_scope_id = 0;
    168 
    169 	for (in6p = rawin6pcb.in6p_next;
    170 	     in6p != &rawin6pcb; in6p = in6p->in6p_next) {
    171 		if (in6p->in6p_ip6.ip6_nxt &&
    172 		    in6p->in6p_ip6.ip6_nxt != proto)
    173 			continue;
    174 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
    175 		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
    176 			continue;
    177 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
    178 		   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
    179 			continue;
    180 		if (in6p->in6p_cksum != -1
    181 		 && in6_cksum(m, ip6->ip6_nxt, *offp, m->m_pkthdr.len - *offp))
    182 		{
    183 			/* XXX bark something */
    184 			continue;
    185 		}
    186 		if (last) {
    187 			struct	mbuf *n;
    188 			if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
    189 				if (last->in6p_flags & IN6P_CONTROLOPTS)
    190 					ip6_savecontrol(last, &opts, ip6, n);
    191 				/* strip intermediate headers */
    192 				m_adj(n, *offp);
    193 				if (sbappendaddr(&last->in6p_socket->so_rcv,
    194 						(struct sockaddr *)&rip6src,
    195 						 n, opts) == 0) {
    196 					/* should notify about lost packet */
    197 					m_freem(n);
    198 					if (opts)
    199 						m_freem(opts);
    200 				} else
    201 					sorwakeup(last->in6p_socket);
    202 				opts = NULL;
    203 			}
    204 		}
    205 		last = in6p;
    206 	}
    207 	if (last) {
    208 		if (last->in6p_flags & IN6P_CONTROLOPTS)
    209 			ip6_savecontrol(last, &opts, ip6, m);
    210 		/* strip intermediate headers */
    211 		m_adj(m, *offp);
    212 		if (sbappendaddr(&last->in6p_socket->so_rcv,
    213 				(struct sockaddr *)&rip6src, m, opts) == 0) {
    214 			m_freem(m);
    215 			if (opts)
    216 				m_freem(opts);
    217 		} else
    218 			sorwakeup(last->in6p_socket);
    219 	} else {
    220 		if (proto == IPPROTO_NONE)
    221 			m_freem(m);
    222 		else {
    223 			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
    224 			icmp6_error(m, ICMP6_PARAM_PROB,
    225 				    ICMP6_PARAMPROB_NEXTHEADER,
    226 				    prvnxtp - mtod(m, char *));
    227 		}
    228 		ip6stat.ip6s_delivered--;
    229 	}
    230 	return IPPROTO_DONE;
    231 }
    232 
    233 /*
    234  * Generate IPv6 header and pass packet to ip6_output.
    235  * Tack on options user may have setup with control call.
    236  */
    237 int
    238 #if __STDC__
    239 rip6_output(struct mbuf *m, ...)
    240 #else
    241 rip6_output(m, va_alist)
    242 	struct mbuf *m;
    243 	va_dcl
    244 #endif
    245 {
    246 	struct socket *so;
    247 	struct sockaddr_in6 *dstsock;
    248 	struct mbuf *control;
    249 	struct in6_addr *dst;
    250 	struct ip6_hdr *ip6;
    251 	struct in6pcb *in6p;
    252 	u_int	plen = m->m_pkthdr.len;
    253 	int error = 0;
    254 	struct ip6_pktopts opt, *optp = NULL;
    255 	struct ifnet *oifp = NULL;
    256 	int type, code;		/* for ICMPv6 output statistics only */
    257 	int priv;
    258 	va_list ap;
    259 
    260 	va_start(ap, m);
    261 	so = va_arg(ap, struct socket *);
    262 	dstsock = va_arg(ap, struct sockaddr_in6 *);
    263 	control = va_arg(ap, struct mbuf *);
    264 	va_end(ap);
    265 
    266 	in6p = sotoin6pcb(so);
    267 
    268 	priv = 0;
    269     {
    270 	struct proc *p = curproc;	/* XXX */
    271 
    272 	if (p && !suser(p->p_ucred, &p->p_acflag))
    273 		priv = 1;
    274     }
    275 	dst = &dstsock->sin6_addr;
    276 	if (control) {
    277 		if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
    278 			goto bad;
    279 		optp = &opt;
    280 	} else
    281 		optp = in6p->in6p_outputopts;
    282 
    283 	/*
    284 	 * For an ICMPv6 packet, we should know its type and code
    285 	 * to update statistics.
    286 	 */
    287 	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
    288 		struct icmp6_hdr *icmp6;
    289 		if (m->m_len < sizeof(struct icmp6_hdr) &&
    290 		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
    291 			error = ENOBUFS;
    292 			goto bad;
    293 		}
    294 		icmp6 = mtod(m, struct icmp6_hdr *);
    295 		type = icmp6->icmp6_type;
    296 		code = icmp6->icmp6_code;
    297 	}
    298 
    299 	M_PREPEND(m, sizeof(*ip6), M_WAIT);
    300 	ip6 = mtod(m, struct ip6_hdr *);
    301 
    302 	/*
    303 	 * Next header might not be ICMP6 but use its pseudo header anyway.
    304 	 */
    305 	ip6->ip6_dst = *dst;
    306 
    307 	/*
    308 	 * If the scope of the destination is link-local, embed the interface
    309 	 * index in the address.
    310 	 *
    311 	 * XXX advanced-api value overrides sin6_scope_id
    312 	 */
    313 	if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
    314 	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
    315 		struct in6_pktinfo *pi;
    316 
    317 		/*
    318 		 * XXX Boundary check is assumed to be already done in
    319 		 * ip6_setpktoptions().
    320 		 */
    321 		if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
    322 			ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
    323 			oifp = ifindex2ifnet[pi->ipi6_ifindex];
    324 		}
    325 		else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
    326 			 in6p->in6p_moptions &&
    327 			 in6p->in6p_moptions->im6o_multicast_ifp) {
    328 			oifp = in6p->in6p_moptions->im6o_multicast_ifp;
    329 			ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
    330 		} else if (dstsock->sin6_scope_id) {
    331 			/* boundary check */
    332 			if (dstsock->sin6_scope_id < 0
    333 			 || if_index < dstsock->sin6_scope_id) {
    334 				error = ENXIO;  /* XXX EINVAL? */
    335 				goto bad;
    336 			}
    337 			ip6->ip6_dst.s6_addr16[1]
    338 				= htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
    339 		}
    340 	}
    341 
    342 	/*
    343 	 * Source address selection.
    344 	 */
    345 	{
    346 		struct in6_addr *in6a;
    347 
    348 		if ((in6a = in6_selectsrc(dstsock, optp,
    349 					  in6p->in6p_moptions,
    350 					  &in6p->in6p_route,
    351 					  &in6p->in6p_laddr,
    352 					  &error)) == 0) {
    353 			if (error == 0)
    354 				error = EADDRNOTAVAIL;
    355 			goto bad;
    356 		}
    357 		ip6->ip6_src = *in6a;
    358 		if (in6p->in6p_route.ro_rt)
    359 			oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
    360 	}
    361 
    362 	ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
    363 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
    364 	ip6->ip6_vfc |= IPV6_VERSION;
    365 #if 0				/* ip6_plen will be filled in ip6_output. */
    366 	ip6->ip6_plen  = htons((u_short)plen);
    367 #endif
    368 	ip6->ip6_nxt   = in6p->in6p_ip6.ip6_nxt;
    369 	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
    370 
    371 	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
    372 	    in6p->in6p_cksum != -1) {
    373 		struct mbuf *n;
    374 		int off;
    375 		u_int16_t *p;
    376 
    377 #define	offsetof(type, member)	((size_t)(&((type *)0)->member)) /* XXX */
    378 
    379 		/* compute checksum */
    380 		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
    381 			off = offsetof(struct icmp6_hdr, icmp6_cksum);
    382 		else
    383 			off = in6p->in6p_cksum;
    384 		if (plen < off + 1) {
    385 			error = EINVAL;
    386 			goto bad;
    387 		}
    388 		off += sizeof(struct ip6_hdr);
    389 
    390 		n = m;
    391 		while (n && n->m_len <= off) {
    392 			off -= n->m_len;
    393 			n = n->m_next;
    394 		}
    395 		if (!n)
    396 			goto bad;
    397 		p = (u_int16_t *)(mtod(n, caddr_t) + off);
    398 		*p = 0;
    399 		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
    400 	}
    401 
    402 #ifdef IPSEC
    403 	m->m_pkthdr.rcvif = (struct ifnet *)so;
    404 #endif /*IPSEC*/
    405 
    406 	error = ip6_output(m, optp, &in6p->in6p_route, 0, in6p->in6p_moptions,
    407 			   &oifp);
    408 	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
    409 		if (oifp)
    410 			icmp6_ifoutstat_inc(oifp, type, code);
    411 		icmp6stat.icp6s_outhist[type]++;
    412 	}
    413 
    414 	goto freectl;
    415 
    416  bad:
    417 	if (m)
    418 		m_freem(m);
    419 
    420  freectl:
    421 	if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
    422 		RTFREE(optp->ip6po_route.ro_rt);
    423 	if (control)
    424 		m_freem(control);
    425 	return(error);
    426 }
    427 
    428 /*
    429  * Raw IPv6 socket option processing.
    430  */
    431 int
    432 rip6_ctloutput(op, so, level, optname, m)
    433 	int op;
    434 	struct socket *so;
    435 	int level, optname;
    436 	struct mbuf **m;
    437 {
    438 	int error = 0;
    439 
    440 	switch(level) {
    441 	 case IPPROTO_IPV6:
    442 		 switch(optname) {
    443 		  case MRT6_INIT:
    444 		  case MRT6_DONE:
    445 		  case MRT6_ADD_MIF:
    446 		  case MRT6_DEL_MIF:
    447 		  case MRT6_ADD_MFC:
    448 		  case MRT6_DEL_MFC:
    449 		  case MRT6_PIM:
    450 			  if (op == PRCO_SETOPT) {
    451 				  error = ip6_mrouter_set(optname, so, *m);
    452 				  if (*m)
    453 					  (void)m_free(*m);
    454 			  } else if (op == PRCO_GETOPT) {
    455 				  error = ip6_mrouter_get(optname, so, m);
    456 			  } else
    457 				  error = EINVAL;
    458 			  return (error);
    459 		 }
    460 		 return (ip6_ctloutput(op, so, level, optname, m));
    461 		 /* NOTREACHED */
    462 
    463 	 case IPPROTO_ICMPV6:
    464 		 /*
    465 		  * XXX: is it better to call icmp6_ctloutput() directly
    466 		  * from protosw?
    467 		  */
    468 		 return(icmp6_ctloutput(op, so, level, optname, m));
    469 
    470 	 default:
    471 		 if (op == PRCO_SETOPT && *m)
    472 			 (void)m_free(*m);
    473 		 return(EINVAL);
    474 	}
    475 }
    476 
    477 extern	u_long rip6_sendspace;
    478 extern	u_long rip6_recvspace;
    479 
    480 int
    481 rip6_usrreq(so, req, m, nam, control, p)
    482 	register struct socket *so;
    483 	int req;
    484 	struct mbuf *m, *nam, *control;
    485 	struct proc *p;
    486 {
    487 	register struct in6pcb *in6p = sotoin6pcb(so);
    488 	int s;
    489 	int error = 0;
    490 /*	extern	struct socket *ip6_mrouter; */ /* xxx */
    491 	int priv;
    492 
    493 	priv = 0;
    494 	if (p && !suser(p->p_ucred, &p->p_acflag))
    495 		priv++;
    496 
    497 	if (req == PRU_CONTROL)
    498 		return (in6_control(so, (u_long)m, (caddr_t)nam,
    499 				    (struct ifnet *)control, p));
    500 
    501 	switch (req) {
    502 	case PRU_ATTACH:
    503 		if (in6p)
    504 			panic("rip6_attach");
    505 		if (!priv) {
    506 			error = EACCES;
    507 			break;
    508 		}
    509 		s = splsoftnet();
    510 		if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) ||
    511 		    (error = in6_pcballoc(so, &rawin6pcb))) {
    512 			splx(s);
    513 			break;
    514 		}
    515 		splx(s);
    516 		in6p = sotoin6pcb(so);
    517 		in6p->in6p_ip6.ip6_nxt = (long)nam;
    518 		in6p->in6p_cksum = -1;
    519 #ifdef IPSEC
    520 		error = ipsec_init_policy(&in6p->in6p_sp);
    521 		if (error != 0) {
    522 			in6_pcbdetach(in6p);
    523 			break;
    524 		}
    525 #endif /*IPSEC*/
    526 
    527 		MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
    528 			sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
    529 		if (in6p->in6p_icmp6filt == NULL) {
    530 			in6_pcbdetach(in6p);
    531 			error = ENOMEM;
    532 			break;
    533 		}
    534 		ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
    535 		break;
    536 
    537 	case PRU_DISCONNECT:
    538 		if ((so->so_state & SS_ISCONNECTED) == 0) {
    539 			error = ENOTCONN;
    540 			break;
    541 		}
    542 		in6p->in6p_faddr = in6addr_any;
    543 		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
    544 		break;
    545 
    546 	case PRU_ABORT:
    547 		soisdisconnected(so);
    548 		/* Fallthrough */
    549 	case PRU_DETACH:
    550 		if (in6p == 0)
    551 			panic("rip6_detach");
    552 		if (so == ip6_mrouter)
    553 			ip6_mrouter_done();
    554 		/* xxx: RSVP */
    555 		if (in6p->in6p_icmp6filt) {
    556 			FREE(in6p->in6p_icmp6filt, M_PCB);
    557 			in6p->in6p_icmp6filt = NULL;
    558 		}
    559 		in6_pcbdetach(in6p);
    560 		break;
    561 
    562 	case PRU_BIND:
    563 	    {
    564 		struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
    565 		struct ifaddr *ia = NULL;
    566 
    567 		if (nam->m_len != sizeof(*addr)) {
    568 			error = EINVAL;
    569 			break;
    570 		}
    571 		if ((ifnet.tqh_first == 0) ||
    572 		   (addr->sin6_family != AF_INET6) ||
    573 		   (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
    574 		    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)) {
    575 			error = EADDRNOTAVAIL;
    576 			break;
    577 		}
    578 		if (ia &&
    579 		    ((struct in6_ifaddr *)ia)->ia6_flags &
    580 		    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
    581 		     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
    582 			error = EADDRNOTAVAIL;
    583 			break;
    584 		}
    585 		in6p->in6p_laddr = addr->sin6_addr;
    586 		break;
    587 	    }
    588 
    589 	case PRU_CONNECT:
    590 	    {
    591 		struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
    592 		struct in6_addr *in6a = NULL;
    593 
    594 		if (nam->m_len != sizeof(*addr)) {
    595 			error = EINVAL;
    596 			break;
    597 		}
    598 		if (ifnet.tqh_first == 0) {
    599 			error = EADDRNOTAVAIL;
    600 			break;
    601 		}
    602 		if (addr->sin6_family != AF_INET6) {
    603 			error = EAFNOSUPPORT;
    604 			break;
    605 		}
    606 
    607 		/* Source address selection. XXX: need pcblookup? */
    608 		in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
    609 				     in6p->in6p_moptions,
    610 				     &in6p->in6p_route,
    611 				     &in6p->in6p_laddr,
    612 				     &error);
    613 		if (in6a == NULL) {
    614 			if (error == 0)
    615 				error = EADDRNOTAVAIL;
    616 			break;
    617 		}
    618 		in6p->in6p_laddr = *in6a;
    619 		in6p->in6p_faddr = addr->sin6_addr;
    620 		soisconnected(so);
    621 		break;
    622 	    }
    623 
    624 	case PRU_CONNECT2:
    625 		error = EOPNOTSUPP;
    626 		break;
    627 
    628 	/*
    629 	 * Mark the connection as being incapable of futther input.
    630 	 */
    631 	case PRU_SHUTDOWN:
    632 		socantsendmore(so);
    633 		break;
    634 	/*
    635 	 * Ship a packet out. The appropriate raw output
    636 	 * routine handles any messaging necessary.
    637 	 */
    638 	case PRU_SEND:
    639 	    {
    640 		struct sockaddr_in6 tmp;
    641 		struct sockaddr_in6 *dst;
    642 
    643 		if (so->so_state & SS_ISCONNECTED) {
    644 			if (nam) {
    645 				error = EISCONN;
    646 				break;
    647 			}
    648 			/* XXX */
    649 			bzero(&tmp, sizeof(tmp));
    650 			tmp.sin6_family = AF_INET6;
    651 			tmp.sin6_len = sizeof(struct sockaddr_in6);
    652 			bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
    653 				sizeof(struct in6_addr));
    654 			dst = &tmp;
    655 		} else {
    656 			if (nam == NULL) {
    657 				error = ENOTCONN;
    658 				break;
    659 			}
    660 			dst = mtod(nam, struct sockaddr_in6 *);
    661 		}
    662 		error = rip6_output(m, so, dst, control);
    663 		m = NULL;
    664 		break;
    665 	    }
    666 
    667 	case PRU_SENSE:
    668 		/*
    669 		 * stat: don't bother with a blocksize
    670 		 */
    671 		return(0);
    672 	/*
    673 	 * Not supported.
    674 	 */
    675 	case PRU_RCVOOB:
    676 	case PRU_RCVD:
    677 	case PRU_LISTEN:
    678 	case PRU_ACCEPT:
    679 	case PRU_SENDOOB:
    680 		error = EOPNOTSUPP;
    681 		break;
    682 
    683 	case PRU_SOCKADDR:
    684 		in6_setsockaddr(in6p, nam);
    685 		break;
    686 
    687 	case PRU_PEERADDR:
    688 		in6_setpeeraddr(in6p, nam);
    689 		break;
    690 
    691 	default:
    692 		panic("rip6_usrreq");
    693 	}
    694 	if (m != NULL)
    695 		m_freem(m);
    696 	return(error);
    697 }
    698