raw_ip6.c revision 195699
1111500Sobrien/*-
2111500Sobrien * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3111500Sobrien * All rights reserved.
4111500Sobrien *
5111500Sobrien * Redistribution and use in source and binary forms, with or without
6111500Sobrien * modification, are permitted provided that the following conditions
7111500Sobrien * are met:
8111500Sobrien * 1. Redistributions of source code must retain the above copyright
9111500Sobrien *    notice, this list of conditions and the following disclaimer.
10111500Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11111500Sobrien *    notice, this list of conditions and the following disclaimer in the
12111500Sobrien *    documentation and/or other materials provided with the distribution.
13111500Sobrien * 3. Neither the name of the project nor the names of its contributors
14111500Sobrien *    may be used to endorse or promote products derived from this software
15111500Sobrien *    without specific prior written permission.
16111500Sobrien *
17111500Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18111500Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19111500Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20117121Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21111500Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22111500Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23111500Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24111500Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25111500Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26111500Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27111500Sobrien * SUCH DAMAGE.
28111500Sobrien */
29111500Sobrien
30111500Sobrien/*-
31111500Sobrien * Copyright (c) 1982, 1986, 1988, 1993
32111500Sobrien *	The Regents of the University of California.
33111500Sobrien * All rights reserved.
34111500Sobrien *
35111500Sobrien * Redistribution and use in source and binary forms, with or without
36111500Sobrien * modification, are permitted provided that the following conditions
37111500Sobrien * are met:
38111500Sobrien * 1. Redistributions of source code must retain the above copyright
39111500Sobrien *    notice, this list of conditions and the following disclaimer.
40111500Sobrien * 2. Redistributions in binary form must reproduce the above copyright
41111500Sobrien *    notice, this list of conditions and the following disclaimer in the
42111500Sobrien *    documentation and/or other materials provided with the distribution.
43133909Smarius * 4. Neither the name of the University nor the names of its contributors
44137814Smarius *    may be used to endorse or promote products derived from this software
45137822Smarius *    without specific prior written permission.
46137822Smarius *
47111500Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48111500Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49111500Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50111500Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51111500Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52136301Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53143827Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54146483Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55146483Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56133909Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57133909Smarius * SUCH DAMAGE.
58133909Smarius *
59133909Smarius *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
60111500Sobrien */
61111500Sobrien
62111500Sobrien#include <sys/cdefs.h>
63111500Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/raw_ip6.c 195699 2009-07-14 22:48:30Z rwatson $");
64111500Sobrien
65111500Sobrien#include "opt_ipsec.h"
66111500Sobrien#include "opt_inet6.h"
67111500Sobrien
68111500Sobrien#include <sys/param.h>
69111500Sobrien#include <sys/errno.h>
70111500Sobrien#include <sys/jail.h>
71111500Sobrien#include <sys/lock.h>
72140243Sru#include <sys/malloc.h>
73111500Sobrien#include <sys/mbuf.h>
74111500Sobrien#include <sys/priv.h>
75111500Sobrien#include <sys/proc.h>
76111500Sobrien#include <sys/protosw.h>
77137812Smarius#include <sys/signalvar.h>
78137812Smarius#include <sys/socket.h>
79137812Smarius#include <sys/socketvar.h>
80133909Smarius#include <sys/sx.h>
81137812Smarius#include <sys/syslog.h>
82133909Smarius#include <sys/vimage.h>
83137812Smarius
84137812Smarius#include <net/if.h>
85137812Smarius#include <net/if_types.h>
86133909Smarius#include <net/route.h>
87137812Smarius#include <net/vnet.h>
88133909Smarius
89133909Smarius#include <netinet/in.h>
90133909Smarius#include <netinet/in_var.h>
91137812Smarius#include <netinet/in_systm.h>
92133909Smarius#include <netinet/in_pcb.h>
93133909Smarius
94137812Smarius#include <netinet/icmp6.h>
95137812Smarius#include <netinet/ip6.h>
96133909Smarius#include <netinet6/ip6protosw.h>
97133909Smarius#include <netinet6/ip6_mroute.h>
98137812Smarius#include <netinet6/in6_pcb.h>
99137812Smarius#include <netinet6/ip6_var.h>
100137812Smarius#include <netinet6/nd6.h>
101133909Smarius#include <netinet6/raw_ip6.h>
102137812Smarius#include <netinet6/scope6_var.h>
103133909Smarius
104111500Sobrien#ifdef IPSEC
105111500Sobrien#include <netipsec/ipsec.h>
106111500Sobrien#include <netipsec/ipsec6.h>
107111500Sobrien#endif /* IPSEC */
108111500Sobrien
109133909Smarius#include <machine/stdarg.h>
110111582Sru
111111582Sru#define	satosin6(sa)	((struct sockaddr_in6 *)(sa))
112111582Sru#define	ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
113111582Sru
114111582Sru/*
115133909Smarius * Raw interface to IP6 protocol.
116133909Smarius */
117133909Smarius
118111582SruVNET_DECLARE(struct inpcbhead, ripcb);
119111582SruVNET_DECLARE(struct inpcbinfo, ripcbinfo);
120111582Sru#define	V_ripcb				VNET_GET(ripcb)
121111582Sru#define	V_ripcbinfo			VNET_GET(ripcbinfo)
122111582Sru
123111582SruVNET_DEFINE(struct rip6stat, rip6stat);
124111582Sru
125111582Sruextern u_long	rip_sendspace;
126111582Sruextern u_long	rip_recvspace;
127111582Sru
128111582Sru/*
129111582Sru * Hooks for multicast routing. They all default to NULL, so leave them not
130111582Sru * initialized and rely on BSS being set to 0.
131111582Sru */
132111582Sru
133111582Sru/*
134111582Sru * The socket used to communicate with the multicast routing daemon.
135111582Sru */
136111582SruVNET_DEFINE(struct socket *, ip6_mrouter);
137111582Sru
138111582Sru/*
139111582Sru * The various mrouter functions.
140111582Sru */
141111582Sruint (*ip6_mrouter_set)(struct socket *, struct sockopt *);
142111582Sruint (*ip6_mrouter_get)(struct socket *, struct sockopt *);
143111582Sruint (*ip6_mrouter_done)(void);
144111582Sruint (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
145int (*mrt6_ioctl)(u_long, caddr_t);
146
147/*
148 * Setup generic address and protocol structures for raw_input routine, then
149 * pass them along with mbuf chain.
150 */
151int
152rip6_input(struct mbuf **mp, int *offp, int proto)
153{
154	struct ifnet *ifp;
155	struct mbuf *m = *mp;
156	register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
157	register struct inpcb *in6p;
158	struct inpcb *last = 0;
159	struct mbuf *opts = NULL;
160	struct sockaddr_in6 fromsa;
161
162	V_rip6stat.rip6s_ipackets++;
163
164	if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
165		/* XXX Send icmp6 host/port unreach? */
166		m_freem(m);
167		return (IPPROTO_DONE);
168	}
169
170	init_sin6(&fromsa, m); /* general init */
171
172	ifp = m->m_pkthdr.rcvif;
173
174	INP_INFO_RLOCK(&V_ripcbinfo);
175	LIST_FOREACH(in6p, &V_ripcb, inp_list) {
176		/* XXX inp locking */
177		if ((in6p->inp_vflag & INP_IPV6) == 0)
178			continue;
179		if (in6p->inp_ip_p &&
180		    in6p->inp_ip_p != proto)
181			continue;
182		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
183		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
184			continue;
185		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
186		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
187			continue;
188		if (jailed(in6p->inp_cred)) {
189			/*
190			 * Allow raw socket in jail to receive multicast;
191			 * assume process had PRIV_NETINET_RAW at attach,
192			 * and fall through into normal filter path if so.
193			 */
194			if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
195			    prison_check_ip6(in6p->inp_cred,
196			    &ip6->ip6_dst) != 0)
197				continue;
198		}
199		if (in6p->in6p_cksum != -1) {
200			V_rip6stat.rip6s_isum++;
201			if (in6_cksum(m, proto, *offp,
202			    m->m_pkthdr.len - *offp)) {
203				INP_RUNLOCK(in6p);
204				V_rip6stat.rip6s_badsum++;
205				continue;
206			}
207		}
208		INP_RLOCK(in6p);
209		/*
210		 * If this raw socket has multicast state, and we
211		 * have received a multicast, check if this socket
212		 * should receive it, as multicast filtering is now
213		 * the responsibility of the transport layer.
214		 */
215		if (in6p->in6p_moptions &&
216		    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
217			struct sockaddr_in6 mcaddr;
218			int blocked;
219
220			bzero(&mcaddr, sizeof(struct sockaddr_in6));
221			mcaddr.sin6_len = sizeof(struct sockaddr_in6);
222			mcaddr.sin6_family = AF_INET6;
223			mcaddr.sin6_addr = ip6->ip6_dst;
224
225			blocked = im6o_mc_filter(in6p->in6p_moptions, ifp,
226			    (struct sockaddr *)&mcaddr,
227			    (struct sockaddr *)&fromsa);
228			if (blocked != MCAST_PASS) {
229				IP6STAT_INC(ip6s_notmember);
230				continue;
231			}
232		}
233		if (last != NULL) {
234			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
235
236#ifdef IPSEC
237			/*
238			 * Check AH/ESP integrity.
239			 */
240			if (n && ipsec6_in_reject(n, last)) {
241				m_freem(n);
242				V_ipsec6stat.in_polvio++;
243				/* Do not inject data into pcb. */
244			} else
245#endif /* IPSEC */
246			if (n) {
247				if (last->inp_flags & INP_CONTROLOPTS ||
248				    last->inp_socket->so_options & SO_TIMESTAMP)
249					ip6_savecontrol(last, n, &opts);
250				/* strip intermediate headers */
251				m_adj(n, *offp);
252				if (sbappendaddr(&last->inp_socket->so_rcv,
253						(struct sockaddr *)&fromsa,
254						 n, opts) == 0) {
255					m_freem(n);
256					if (opts)
257						m_freem(opts);
258					V_rip6stat.rip6s_fullsock++;
259				} else
260					sorwakeup(last->inp_socket);
261				opts = NULL;
262			}
263			INP_RUNLOCK(last);
264		}
265		last = in6p;
266	}
267	INP_INFO_RUNLOCK(&V_ripcbinfo);
268#ifdef IPSEC
269	/*
270	 * Check AH/ESP integrity.
271	 */
272	if ((last != NULL) && ipsec6_in_reject(m, last)) {
273		m_freem(m);
274		V_ipsec6stat.in_polvio++;
275		V_ip6stat.ip6s_delivered--;
276		/* Do not inject data into pcb. */
277		INP_RUNLOCK(last);
278	} else
279#endif /* IPSEC */
280	if (last != NULL) {
281		if (last->inp_flags & INP_CONTROLOPTS ||
282		    last->inp_socket->so_options & SO_TIMESTAMP)
283			ip6_savecontrol(last, m, &opts);
284		/* Strip intermediate headers. */
285		m_adj(m, *offp);
286		if (sbappendaddr(&last->inp_socket->so_rcv,
287		    (struct sockaddr *)&fromsa, m, opts) == 0) {
288			m_freem(m);
289			if (opts)
290				m_freem(opts);
291			V_rip6stat.rip6s_fullsock++;
292		} else
293			sorwakeup(last->inp_socket);
294		INP_RUNLOCK(last);
295	} else {
296		V_rip6stat.rip6s_nosock++;
297		if (m->m_flags & M_MCAST)
298			V_rip6stat.rip6s_nosockmcast++;
299		if (proto == IPPROTO_NONE)
300			m_freem(m);
301		else {
302			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
303			icmp6_error(m, ICMP6_PARAM_PROB,
304			    ICMP6_PARAMPROB_NEXTHEADER,
305			    prvnxtp - mtod(m, char *));
306		}
307		V_ip6stat.ip6s_delivered--;
308	}
309	return (IPPROTO_DONE);
310}
311
312void
313rip6_ctlinput(int cmd, struct sockaddr *sa, void *d)
314{
315	struct ip6_hdr *ip6;
316	struct mbuf *m;
317	int off = 0;
318	struct ip6ctlparam *ip6cp = NULL;
319	const struct sockaddr_in6 *sa6_src = NULL;
320	void *cmdarg;
321	struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
322
323	if (sa->sa_family != AF_INET6 ||
324	    sa->sa_len != sizeof(struct sockaddr_in6))
325		return;
326
327	if ((unsigned)cmd >= PRC_NCMDS)
328		return;
329	if (PRC_IS_REDIRECT(cmd))
330		notify = in6_rtchange, d = NULL;
331	else if (cmd == PRC_HOSTDEAD)
332		d = NULL;
333	else if (inet6ctlerrmap[cmd] == 0)
334		return;
335
336	/*
337	 * If the parameter is from icmp6, decode it.
338	 */
339	if (d != NULL) {
340		ip6cp = (struct ip6ctlparam *)d;
341		m = ip6cp->ip6c_m;
342		ip6 = ip6cp->ip6c_ip6;
343		off = ip6cp->ip6c_off;
344		cmdarg = ip6cp->ip6c_cmdarg;
345		sa6_src = ip6cp->ip6c_src;
346	} else {
347		m = NULL;
348		ip6 = NULL;
349		cmdarg = NULL;
350		sa6_src = &sa6_any;
351	}
352
353	(void) in6_pcbnotify(&V_ripcbinfo, sa, 0,
354	    (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
355}
356
357/*
358 * Generate IPv6 header and pass packet to ip6_output.  Tack on options user
359 * may have setup with control call.
360 */
361int
362#if __STDC__
363rip6_output(struct mbuf *m, ...)
364#else
365rip6_output(m, va_alist)
366	struct mbuf *m;
367	va_dcl
368#endif
369{
370	struct mbuf *control;
371	struct socket *so;
372	struct sockaddr_in6 *dstsock;
373	struct in6_addr *dst;
374	struct ip6_hdr *ip6;
375	struct inpcb *in6p;
376	u_int	plen = m->m_pkthdr.len;
377	int error = 0;
378	struct ip6_pktopts opt, *optp;
379	struct ifnet *oifp = NULL;
380	int type = 0, code = 0;		/* for ICMPv6 output statistics only */
381	int scope_ambiguous = 0;
382	struct in6_addr in6a;
383	va_list ap;
384
385	va_start(ap, m);
386	so = va_arg(ap, struct socket *);
387	dstsock = va_arg(ap, struct sockaddr_in6 *);
388	control = va_arg(ap, struct mbuf *);
389	va_end(ap);
390
391	in6p = sotoinpcb(so);
392	INP_WLOCK(in6p);
393
394	dst = &dstsock->sin6_addr;
395	if (control != NULL) {
396		if ((error = ip6_setpktopts(control, &opt,
397		    in6p->in6p_outputopts, so->so_cred,
398		    so->so_proto->pr_protocol)) != 0) {
399			goto bad;
400		}
401		optp = &opt;
402	} else
403		optp = in6p->in6p_outputopts;
404
405	/*
406	 * Check and convert scope zone ID into internal form.
407	 *
408	 * XXX: we may still need to determine the zone later.
409	 */
410	if (!(so->so_state & SS_ISCONNECTED)) {
411		if (dstsock->sin6_scope_id == 0 && !V_ip6_use_defzone)
412			scope_ambiguous = 1;
413		if ((error = sa6_embedscope(dstsock, V_ip6_use_defzone)) != 0)
414			goto bad;
415	}
416
417	/*
418	 * For an ICMPv6 packet, we should know its type and code to update
419	 * statistics.
420	 */
421	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
422		struct icmp6_hdr *icmp6;
423		if (m->m_len < sizeof(struct icmp6_hdr) &&
424		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
425			error = ENOBUFS;
426			goto bad;
427		}
428		icmp6 = mtod(m, struct icmp6_hdr *);
429		type = icmp6->icmp6_type;
430		code = icmp6->icmp6_code;
431	}
432
433	M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
434	if (m == NULL) {
435		error = ENOBUFS;
436		goto bad;
437	}
438	ip6 = mtod(m, struct ip6_hdr *);
439
440	/*
441	 * Source address selection.
442	 */
443	error = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
444	    &oifp, &in6a);
445	if (error)
446		goto bad;
447	error = prison_get_ip6(in6p->inp_cred, &in6a);
448	if (error != 0)
449		goto bad;
450	ip6->ip6_src = in6a;
451
452	if (oifp && scope_ambiguous) {
453		/*
454		 * Application should provide a proper zone ID or the use of
455		 * default zone IDs should be enabled.  Unfortunately, some
456		 * applications do not behave as it should, so we need a
457		 * workaround.  Even if an appropriate ID is not determined
458		 * (when it's required), if we can determine the outgoing
459		 * interface. determine the zone ID based on the interface.
460		 */
461		error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
462		if (error != 0)
463			goto bad;
464	}
465	ip6->ip6_dst = dstsock->sin6_addr;
466
467	/*
468	 * Fill in the rest of the IPv6 header fields.
469	 */
470	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
471	    (in6p->inp_flow & IPV6_FLOWINFO_MASK);
472	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
473	    (IPV6_VERSION & IPV6_VERSION_MASK);
474
475	/*
476	 * ip6_plen will be filled in ip6_output, so not fill it here.
477	 */
478	ip6->ip6_nxt = in6p->inp_ip_p;
479	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
480
481	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
482	    in6p->in6p_cksum != -1) {
483		struct mbuf *n;
484		int off;
485		u_int16_t *p;
486
487		/* Compute checksum. */
488		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
489			off = offsetof(struct icmp6_hdr, icmp6_cksum);
490		else
491			off = in6p->in6p_cksum;
492		if (plen < off + 1) {
493			error = EINVAL;
494			goto bad;
495		}
496		off += sizeof(struct ip6_hdr);
497
498		n = m;
499		while (n && n->m_len <= off) {
500			off -= n->m_len;
501			n = n->m_next;
502		}
503		if (!n)
504			goto bad;
505		p = (u_int16_t *)(mtod(n, caddr_t) + off);
506		*p = 0;
507		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
508	}
509
510	error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p);
511	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
512		if (oifp)
513			icmp6_ifoutstat_inc(oifp, type, code);
514		ICMP6STAT_INC(icp6s_outhist[type]);
515	} else
516		V_rip6stat.rip6s_opackets++;
517
518	goto freectl;
519
520 bad:
521	if (m)
522		m_freem(m);
523
524 freectl:
525	if (control != NULL) {
526		ip6_clearpktopts(&opt, -1);
527		m_freem(control);
528	}
529	INP_WUNLOCK(in6p);
530	return (error);
531}
532
533/*
534 * Raw IPv6 socket option processing.
535 */
536int
537rip6_ctloutput(struct socket *so, struct sockopt *sopt)
538{
539	int error;
540
541	if (sopt->sopt_level == IPPROTO_ICMPV6)
542		/*
543		 * XXX: is it better to call icmp6_ctloutput() directly
544		 * from protosw?
545		 */
546		return (icmp6_ctloutput(so, sopt));
547	else if (sopt->sopt_level != IPPROTO_IPV6)
548		return (EINVAL);
549
550	error = 0;
551
552	switch (sopt->sopt_dir) {
553	case SOPT_GET:
554		switch (sopt->sopt_name) {
555		case MRT6_INIT:
556		case MRT6_DONE:
557		case MRT6_ADD_MIF:
558		case MRT6_DEL_MIF:
559		case MRT6_ADD_MFC:
560		case MRT6_DEL_MFC:
561		case MRT6_PIM:
562			error = ip6_mrouter_get ?  ip6_mrouter_get(so, sopt) :
563			    EOPNOTSUPP;
564			break;
565		case IPV6_CHECKSUM:
566			error = ip6_raw_ctloutput(so, sopt);
567			break;
568		default:
569			error = ip6_ctloutput(so, sopt);
570			break;
571		}
572		break;
573
574	case SOPT_SET:
575		switch (sopt->sopt_name) {
576		case MRT6_INIT:
577		case MRT6_DONE:
578		case MRT6_ADD_MIF:
579		case MRT6_DEL_MIF:
580		case MRT6_ADD_MFC:
581		case MRT6_DEL_MFC:
582		case MRT6_PIM:
583			error = ip6_mrouter_set ?  ip6_mrouter_set(so, sopt) :
584			    EOPNOTSUPP;
585			break;
586		case IPV6_CHECKSUM:
587			error = ip6_raw_ctloutput(so, sopt);
588			break;
589		default:
590			error = ip6_ctloutput(so, sopt);
591			break;
592		}
593		break;
594	}
595
596	return (error);
597}
598
599static int
600rip6_attach(struct socket *so, int proto, struct thread *td)
601{
602	struct inpcb *inp;
603	struct icmp6_filter *filter;
604	int error;
605
606	inp = sotoinpcb(so);
607	KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
608
609	error = priv_check(td, PRIV_NETINET_RAW);
610	if (error)
611		return (error);
612	error = soreserve(so, rip_sendspace, rip_recvspace);
613	if (error)
614		return (error);
615	filter = malloc(sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
616	if (filter == NULL)
617		return (ENOMEM);
618	INP_INFO_WLOCK(&V_ripcbinfo);
619	error = in_pcballoc(so, &V_ripcbinfo);
620	if (error) {
621		INP_INFO_WUNLOCK(&V_ripcbinfo);
622		free(filter, M_PCB);
623		return (error);
624	}
625	inp = (struct inpcb *)so->so_pcb;
626	INP_INFO_WUNLOCK(&V_ripcbinfo);
627	inp->inp_vflag |= INP_IPV6;
628	inp->inp_ip_p = (long)proto;
629	inp->in6p_hops = -1;	/* use kernel default */
630	inp->in6p_cksum = -1;
631	inp->in6p_icmp6filt = filter;
632	ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
633	INP_WUNLOCK(inp);
634	return (0);
635}
636
637static void
638rip6_detach(struct socket *so)
639{
640	struct inpcb *inp;
641
642	inp = sotoinpcb(so);
643	KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
644
645	if (so == V_ip6_mrouter && ip6_mrouter_done)
646		ip6_mrouter_done();
647	/* xxx: RSVP */
648	INP_INFO_WLOCK(&V_ripcbinfo);
649	INP_WLOCK(inp);
650	free(inp->in6p_icmp6filt, M_PCB);
651	in_pcbdetach(inp);
652	in_pcbfree(inp);
653	INP_INFO_WUNLOCK(&V_ripcbinfo);
654}
655
656/* XXXRW: This can't ever be called. */
657static void
658rip6_abort(struct socket *so)
659{
660	struct inpcb *inp;
661
662	inp = sotoinpcb(so);
663	KASSERT(inp != NULL, ("rip6_abort: inp == NULL"));
664
665	soisdisconnected(so);
666}
667
668static void
669rip6_close(struct socket *so)
670{
671	struct inpcb *inp;
672
673	inp = sotoinpcb(so);
674	KASSERT(inp != NULL, ("rip6_close: inp == NULL"));
675
676	soisdisconnected(so);
677}
678
679static int
680rip6_disconnect(struct socket *so)
681{
682	struct inpcb *inp;
683
684	inp = sotoinpcb(so);
685	KASSERT(inp != NULL, ("rip6_disconnect: inp == NULL"));
686
687	if ((so->so_state & SS_ISCONNECTED) == 0)
688		return (ENOTCONN);
689	inp->in6p_faddr = in6addr_any;
690	rip6_abort(so);
691	return (0);
692}
693
694static int
695rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
696{
697	struct inpcb *inp;
698	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
699	struct ifaddr *ifa = NULL;
700	int error = 0;
701
702	inp = sotoinpcb(so);
703	KASSERT(inp != NULL, ("rip6_bind: inp == NULL"));
704
705	if (nam->sa_len != sizeof(*addr))
706		return (EINVAL);
707	if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0)
708		return (error);
709	if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
710		return (EADDRNOTAVAIL);
711	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
712		return (error);
713
714	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
715	    (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
716		return (EADDRNOTAVAIL);
717	if (ifa != NULL &&
718	    ((struct in6_ifaddr *)ifa)->ia6_flags &
719	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
720	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
721		ifa_free(ifa);
722		return (EADDRNOTAVAIL);
723	}
724	if (ifa != NULL)
725		ifa_free(ifa);
726	INP_INFO_WLOCK(&V_ripcbinfo);
727	INP_WLOCK(inp);
728	inp->in6p_laddr = addr->sin6_addr;
729	INP_WUNLOCK(inp);
730	INP_INFO_WUNLOCK(&V_ripcbinfo);
731	return (0);
732}
733
734static int
735rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
736{
737	struct inpcb *inp;
738	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
739	struct in6_addr in6a;
740	struct ifnet *ifp = NULL;
741	int error = 0, scope_ambiguous = 0;
742
743	inp = sotoinpcb(so);
744	KASSERT(inp != NULL, ("rip6_connect: inp == NULL"));
745
746	if (nam->sa_len != sizeof(*addr))
747		return (EINVAL);
748	if (TAILQ_EMPTY(&V_ifnet))
749		return (EADDRNOTAVAIL);
750	if (addr->sin6_family != AF_INET6)
751		return (EAFNOSUPPORT);
752
753	/*
754	 * Application should provide a proper zone ID or the use of default
755	 * zone IDs should be enabled.  Unfortunately, some applications do
756	 * not behave as it should, so we need a workaround.  Even if an
757	 * appropriate ID is not determined, we'll see if we can determine
758	 * the outgoing interface.  If we can, determine the zone ID based on
759	 * the interface below.
760	 */
761	if (addr->sin6_scope_id == 0 && !V_ip6_use_defzone)
762		scope_ambiguous = 1;
763	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
764		return (error);
765
766	INP_INFO_WLOCK(&V_ripcbinfo);
767	INP_WLOCK(inp);
768	/* Source address selection. XXX: need pcblookup? */
769	error = in6_selectsrc(addr, inp->in6p_outputopts,
770	    inp, NULL, so->so_cred, &ifp, &in6a);
771	if (error) {
772		INP_WUNLOCK(inp);
773		INP_INFO_WUNLOCK(&V_ripcbinfo);
774		return (error);
775	}
776
777	/* XXX: see above */
778	if (ifp && scope_ambiguous &&
779	    (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
780		INP_WUNLOCK(inp);
781		INP_INFO_WUNLOCK(&V_ripcbinfo);
782		return (error);
783	}
784	inp->in6p_faddr = addr->sin6_addr;
785	inp->in6p_laddr = in6a;
786	soisconnected(so);
787	INP_WUNLOCK(inp);
788	INP_INFO_WUNLOCK(&V_ripcbinfo);
789	return (0);
790}
791
792static int
793rip6_shutdown(struct socket *so)
794{
795	struct inpcb *inp;
796
797	inp = sotoinpcb(so);
798	KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL"));
799
800	INP_WLOCK(inp);
801	socantsendmore(so);
802	INP_WUNLOCK(inp);
803	return (0);
804}
805
806static int
807rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
808    struct mbuf *control, struct thread *td)
809{
810	struct inpcb *inp;
811	struct sockaddr_in6 tmp;
812	struct sockaddr_in6 *dst;
813	int ret;
814
815	inp = sotoinpcb(so);
816	KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
817
818	/* Always copy sockaddr to avoid overwrites. */
819	/* Unlocked read. */
820	if (so->so_state & SS_ISCONNECTED) {
821		if (nam) {
822			m_freem(m);
823			return (EISCONN);
824		}
825		/* XXX */
826		bzero(&tmp, sizeof(tmp));
827		tmp.sin6_family = AF_INET6;
828		tmp.sin6_len = sizeof(struct sockaddr_in6);
829		INP_RLOCK(inp);
830		bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
831		    sizeof(struct in6_addr));
832		INP_RUNLOCK(inp);
833		dst = &tmp;
834	} else {
835		if (nam == NULL) {
836			m_freem(m);
837			return (ENOTCONN);
838		}
839		if (nam->sa_len != sizeof(struct sockaddr_in6)) {
840			m_freem(m);
841			return (EINVAL);
842		}
843		tmp = *(struct sockaddr_in6 *)nam;
844		dst = &tmp;
845
846		if (dst->sin6_family == AF_UNSPEC) {
847			/*
848			 * XXX: we allow this case for backward
849			 * compatibility to buggy applications that
850			 * rely on old (and wrong) kernel behavior.
851			 */
852			log(LOG_INFO, "rip6 SEND: address family is "
853			    "unspec. Assume AF_INET6\n");
854			dst->sin6_family = AF_INET6;
855		} else if (dst->sin6_family != AF_INET6) {
856			m_freem(m);
857			return(EAFNOSUPPORT);
858		}
859	}
860	ret = rip6_output(m, so, dst, control);
861	return (ret);
862}
863
864struct pr_usrreqs rip6_usrreqs = {
865	.pru_abort =		rip6_abort,
866	.pru_attach =		rip6_attach,
867	.pru_bind =		rip6_bind,
868	.pru_connect =		rip6_connect,
869	.pru_control =		in6_control,
870	.pru_detach =		rip6_detach,
871	.pru_disconnect =	rip6_disconnect,
872	.pru_peeraddr =		in6_getpeeraddr,
873	.pru_send =		rip6_send,
874	.pru_shutdown =		rip6_shutdown,
875	.pru_sockaddr =		in6_getsockaddr,
876	.pru_close =		rip6_close,
877};
878