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