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