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