raw_ip6.c revision 185088
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
30/*-
31 * Copyright (c) 1982, 1986, 1988, 1993
32 *	The Regents of the University of California.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 4. Neither the name of the University nor the names of its contributors
44 *    may be used to endorse or promote products derived from this software
45 *    without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
60 */
61
62#include <sys/cdefs.h>
63__FBSDID("$FreeBSD: head/sys/netinet6/raw_ip6.c 185088 2008-11-19 09:39:34Z zec $");
64
65#include "opt_ipsec.h"
66#include "opt_inet6.h"
67
68#include <sys/param.h>
69#include <sys/errno.h>
70#include <sys/lock.h>
71#include <sys/malloc.h>
72#include <sys/mbuf.h>
73#include <sys/priv.h>
74#include <sys/proc.h>
75#include <sys/protosw.h>
76#include <sys/signalvar.h>
77#include <sys/socket.h>
78#include <sys/socketvar.h>
79#include <sys/sx.h>
80#include <sys/syslog.h>
81#include <sys/vimage.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#include <netinet6/scope6_var.h>
100
101#ifdef IPSEC
102#include <netipsec/ipsec.h>
103#include <netipsec/ipsec6.h>
104#endif /* IPSEC */
105
106#include <machine/stdarg.h>
107
108#define	satosin6(sa)	((struct sockaddr_in6 *)(sa))
109#define	ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
110
111/*
112 * Raw interface to IP6 protocol.
113 */
114
115extern struct	inpcbhead ripcb;
116extern struct	inpcbinfo ripcbinfo;
117extern u_long	rip_sendspace;
118extern u_long	rip_recvspace;
119
120#ifdef VIMAGE_GLOBALS
121struct rip6stat rip6stat;
122#endif
123
124/*
125 * Hooks for multicast forwarding.
126 */
127struct socket *ip6_mrouter = NULL;
128int (*ip6_mrouter_set)(struct socket *, struct sockopt *);
129int (*ip6_mrouter_get)(struct socket *, struct sockopt *);
130int (*ip6_mrouter_done)(void);
131int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
132int (*mrt6_ioctl)(int, caddr_t);
133
134/*
135 * Setup generic address and protocol structures for raw_input routine, then
136 * pass them along with mbuf chain.
137 */
138int
139rip6_input(struct mbuf **mp, int *offp, int proto)
140{
141	INIT_VNET_INET(curvnet);
142	INIT_VNET_INET6(curvnet);
143#ifdef IPSEC
144	INIT_VNET_IPSEC(curvnet);
145#endif
146	struct mbuf *m = *mp;
147	register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
148	register struct inpcb *in6p;
149	struct inpcb *last = 0;
150	struct mbuf *opts = NULL;
151	struct sockaddr_in6 fromsa;
152
153	V_rip6stat.rip6s_ipackets++;
154
155	if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
156		/* XXX Send icmp6 host/port unreach? */
157		m_freem(m);
158		return (IPPROTO_DONE);
159	}
160
161	init_sin6(&fromsa, m); /* general init */
162
163	INP_INFO_RLOCK(&V_ripcbinfo);
164	LIST_FOREACH(in6p, &V_ripcb, inp_list) {
165		if ((in6p->in6p_vflag & INP_IPV6) == 0)
166			continue;
167		if (in6p->in6p_ip6_nxt &&
168		    in6p->in6p_ip6_nxt != proto)
169			continue;
170		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
171		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
172			continue;
173		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
174		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
175			continue;
176		INP_RLOCK(in6p);
177		if (in6p->in6p_cksum != -1) {
178			V_rip6stat.rip6s_isum++;
179			if (in6_cksum(m, proto, *offp,
180			    m->m_pkthdr.len - *offp)) {
181				INP_RUNLOCK(in6p);
182				V_rip6stat.rip6s_badsum++;
183				continue;
184			}
185		}
186		if (last) {
187			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
188
189#ifdef IPSEC
190			/*
191			 * Check AH/ESP integrity.
192			 */
193			if (n && ipsec6_in_reject(n, last)) {
194				m_freem(n);
195				V_ipsec6stat.in_polvio++;
196				/* Do not inject data into pcb. */
197			} else
198#endif /* IPSEC */
199			if (n) {
200				if (last->in6p_flags & IN6P_CONTROLOPTS ||
201				    last->in6p_socket->so_options & SO_TIMESTAMP)
202					ip6_savecontrol(last, n, &opts);
203				/* strip intermediate headers */
204				m_adj(n, *offp);
205				if (sbappendaddr(&last->in6p_socket->so_rcv,
206						(struct sockaddr *)&fromsa,
207						 n, opts) == 0) {
208					m_freem(n);
209					if (opts)
210						m_freem(opts);
211					V_rip6stat.rip6s_fullsock++;
212				} else
213					sorwakeup(last->in6p_socket);
214				opts = NULL;
215			}
216			INP_RUNLOCK(last);
217		}
218		last = in6p;
219	}
220	INP_INFO_RUNLOCK(&V_ripcbinfo);
221#ifdef IPSEC
222	/*
223	 * Check AH/ESP integrity.
224	 */
225	if (last && ipsec6_in_reject(m, last)) {
226		m_freem(m);
227		V_ipsec6stat.in_polvio++;
228		V_ip6stat.ip6s_delivered--;
229		/* Do not inject data into pcb. */
230		INP_RUNLOCK(last);
231	} else
232#endif /* IPSEC */
233	if (last) {
234		if (last->in6p_flags & IN6P_CONTROLOPTS ||
235		    last->in6p_socket->so_options & SO_TIMESTAMP)
236			ip6_savecontrol(last, m, &opts);
237		/* Strip intermediate headers. */
238		m_adj(m, *offp);
239		if (sbappendaddr(&last->in6p_socket->so_rcv,
240		    (struct sockaddr *)&fromsa, m, opts) == 0) {
241			m_freem(m);
242			if (opts)
243				m_freem(opts);
244			V_rip6stat.rip6s_fullsock++;
245		} else
246			sorwakeup(last->in6p_socket);
247		INP_RUNLOCK(last);
248	} else {
249		V_rip6stat.rip6s_nosock++;
250		if (m->m_flags & M_MCAST)
251			V_rip6stat.rip6s_nosockmcast++;
252		if (proto == IPPROTO_NONE)
253			m_freem(m);
254		else {
255			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
256			icmp6_error(m, ICMP6_PARAM_PROB,
257			    ICMP6_PARAMPROB_NEXTHEADER,
258			    prvnxtp - mtod(m, char *));
259		}
260		V_ip6stat.ip6s_delivered--;
261	}
262	return (IPPROTO_DONE);
263}
264
265void
266rip6_ctlinput(int cmd, struct sockaddr *sa, void *d)
267{
268	INIT_VNET_INET(curvnet);
269	struct ip6_hdr *ip6;
270	struct mbuf *m;
271	int off = 0;
272	struct ip6ctlparam *ip6cp = NULL;
273	const struct sockaddr_in6 *sa6_src = NULL;
274	void *cmdarg;
275	struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
276
277	if (sa->sa_family != AF_INET6 ||
278	    sa->sa_len != sizeof(struct sockaddr_in6))
279		return;
280
281	if ((unsigned)cmd >= PRC_NCMDS)
282		return;
283	if (PRC_IS_REDIRECT(cmd))
284		notify = in6_rtchange, d = NULL;
285	else if (cmd == PRC_HOSTDEAD)
286		d = NULL;
287	else if (inet6ctlerrmap[cmd] == 0)
288		return;
289
290	/*
291	 * If the parameter is from icmp6, decode it.
292	 */
293	if (d != NULL) {
294		ip6cp = (struct ip6ctlparam *)d;
295		m = ip6cp->ip6c_m;
296		ip6 = ip6cp->ip6c_ip6;
297		off = ip6cp->ip6c_off;
298		cmdarg = ip6cp->ip6c_cmdarg;
299		sa6_src = ip6cp->ip6c_src;
300	} else {
301		m = NULL;
302		ip6 = NULL;
303		cmdarg = NULL;
304		sa6_src = &sa6_any;
305	}
306
307	(void) in6_pcbnotify(&V_ripcbinfo, sa, 0,
308	    (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
309}
310
311/*
312 * Generate IPv6 header and pass packet to ip6_output.  Tack on options user
313 * may have setup with control call.
314 */
315int
316#if __STDC__
317rip6_output(struct mbuf *m, ...)
318#else
319rip6_output(m, va_alist)
320	struct mbuf *m;
321	va_dcl
322#endif
323{
324	INIT_VNET_INET6(curvnet);
325	struct mbuf *control;
326	struct socket *so;
327	struct sockaddr_in6 *dstsock;
328	struct in6_addr *dst;
329	struct ip6_hdr *ip6;
330	struct inpcb *in6p;
331	u_int	plen = m->m_pkthdr.len;
332	int error = 0;
333	struct ip6_pktopts opt, *optp;
334	struct ifnet *oifp = NULL;
335	int type = 0, code = 0;		/* for ICMPv6 output statistics only */
336	int scope_ambiguous = 0;
337	struct in6_addr *in6a;
338	va_list ap;
339
340	va_start(ap, m);
341	so = va_arg(ap, struct socket *);
342	dstsock = va_arg(ap, struct sockaddr_in6 *);
343	control = va_arg(ap, struct mbuf *);
344	va_end(ap);
345
346	in6p = sotoin6pcb(so);
347	INP_WLOCK(in6p);
348
349	dst = &dstsock->sin6_addr;
350	if (control) {
351		if ((error = ip6_setpktopts(control, &opt,
352		    in6p->in6p_outputopts, so->so_cred,
353		    so->so_proto->pr_protocol)) != 0) {
354			goto bad;
355		}
356		optp = &opt;
357	} else
358		optp = in6p->in6p_outputopts;
359
360	/*
361	 * Check and convert scope zone ID into internal form.
362	 *
363	 * XXX: we may still need to determine the zone later.
364	 */
365	if (!(so->so_state & SS_ISCONNECTED)) {
366		if (dstsock->sin6_scope_id == 0 && !V_ip6_use_defzone)
367			scope_ambiguous = 1;
368		if ((error = sa6_embedscope(dstsock, V_ip6_use_defzone)) != 0)
369			goto bad;
370	}
371
372	/*
373	 * For an ICMPv6 packet, we should know its type and code to update
374	 * statistics.
375	 */
376	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
377		struct icmp6_hdr *icmp6;
378		if (m->m_len < sizeof(struct icmp6_hdr) &&
379		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
380			error = ENOBUFS;
381			goto bad;
382		}
383		icmp6 = mtod(m, struct icmp6_hdr *);
384		type = icmp6->icmp6_type;
385		code = icmp6->icmp6_code;
386	}
387
388	M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
389	if (m == NULL) {
390		error = ENOBUFS;
391		goto bad;
392	}
393	ip6 = mtod(m, struct ip6_hdr *);
394
395	/*
396	 * Source address selection.
397	 */
398	if ((in6a = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
399	    &oifp, &error)) == NULL) {
400		if (error == 0)
401			error = EADDRNOTAVAIL;
402		goto bad;
403	}
404	ip6->ip6_src = *in6a;
405
406	if (oifp && scope_ambiguous) {
407		/*
408		 * Application should provide a proper zone ID or the use of
409		 * default zone IDs should be enabled.  Unfortunately, some
410		 * applications do not behave as it should, so we need a
411		 * workaround.  Even if an appropriate ID is not determined
412		 * (when it's required), if we can determine the outgoing
413		 * interface. determine the zone ID based on the interface.
414		 */
415		error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
416		if (error != 0)
417			goto bad;
418	}
419	ip6->ip6_dst = dstsock->sin6_addr;
420
421	/*
422	 * Fill in the rest of the IPv6 header fields.
423	 */
424	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
425	    (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
426	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
427	    (IPV6_VERSION & IPV6_VERSION_MASK);
428
429	/*
430	 * ip6_plen will be filled in ip6_output, so not fill it here.
431	 */
432	ip6->ip6_nxt = in6p->in6p_ip6_nxt;
433	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
434
435	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
436	    in6p->in6p_cksum != -1) {
437		struct mbuf *n;
438		int off;
439		u_int16_t *p;
440
441		/* Compute checksum. */
442		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
443			off = offsetof(struct icmp6_hdr, icmp6_cksum);
444		else
445			off = in6p->in6p_cksum;
446		if (plen < off + 1) {
447			error = EINVAL;
448			goto bad;
449		}
450		off += sizeof(struct ip6_hdr);
451
452		n = m;
453		while (n && n->m_len <= off) {
454			off -= n->m_len;
455			n = n->m_next;
456		}
457		if (!n)
458			goto bad;
459		p = (u_int16_t *)(mtod(n, caddr_t) + off);
460		*p = 0;
461		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
462	}
463
464	error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p);
465	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
466		if (oifp)
467			icmp6_ifoutstat_inc(oifp, type, code);
468		V_icmp6stat.icp6s_outhist[type]++;
469	} else
470		V_rip6stat.rip6s_opackets++;
471
472	goto freectl;
473
474 bad:
475	if (m)
476		m_freem(m);
477
478 freectl:
479	if (control) {
480		ip6_clearpktopts(&opt, -1);
481		m_freem(control);
482	}
483	INP_WUNLOCK(in6p);
484	return (error);
485}
486
487/*
488 * Raw IPv6 socket option processing.
489 */
490int
491rip6_ctloutput(struct socket *so, struct sockopt *sopt)
492{
493	int error;
494
495	if (sopt->sopt_level == IPPROTO_ICMPV6)
496		/*
497		 * XXX: is it better to call icmp6_ctloutput() directly
498		 * from protosw?
499		 */
500		return (icmp6_ctloutput(so, sopt));
501	else if (sopt->sopt_level != IPPROTO_IPV6)
502		return (EINVAL);
503
504	error = 0;
505
506	switch (sopt->sopt_dir) {
507	case SOPT_GET:
508		switch (sopt->sopt_name) {
509		case MRT6_INIT:
510		case MRT6_DONE:
511		case MRT6_ADD_MIF:
512		case MRT6_DEL_MIF:
513		case MRT6_ADD_MFC:
514		case MRT6_DEL_MFC:
515		case MRT6_PIM:
516			error = ip6_mrouter_get ?  ip6_mrouter_get(so, sopt) :
517			    EOPNOTSUPP;
518			break;
519		case IPV6_CHECKSUM:
520			error = ip6_raw_ctloutput(so, sopt);
521			break;
522		default:
523			error = ip6_ctloutput(so, sopt);
524			break;
525		}
526		break;
527
528	case SOPT_SET:
529		switch (sopt->sopt_name) {
530		case MRT6_INIT:
531		case MRT6_DONE:
532		case MRT6_ADD_MIF:
533		case MRT6_DEL_MIF:
534		case MRT6_ADD_MFC:
535		case MRT6_DEL_MFC:
536		case MRT6_PIM:
537			error = ip6_mrouter_set ?  ip6_mrouter_set(so, sopt) :
538			    EOPNOTSUPP;
539			break;
540		case IPV6_CHECKSUM:
541			error = ip6_raw_ctloutput(so, sopt);
542			break;
543		default:
544			error = ip6_ctloutput(so, sopt);
545			break;
546		}
547		break;
548	}
549
550	return (error);
551}
552
553static int
554rip6_attach(struct socket *so, int proto, struct thread *td)
555{
556	INIT_VNET_INET(so->so_vnet);
557	struct inpcb *inp;
558	struct icmp6_filter *filter;
559	int error;
560
561	inp = sotoinpcb(so);
562	KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
563
564	error = priv_check(td, PRIV_NETINET_RAW);
565	if (error)
566		return (error);
567	error = soreserve(so, rip_sendspace, rip_recvspace);
568	if (error)
569		return (error);
570	filter = malloc(sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
571	if (filter == NULL)
572		return (ENOMEM);
573	INP_INFO_WLOCK(&V_ripcbinfo);
574	error = in_pcballoc(so, &V_ripcbinfo);
575	if (error) {
576		INP_INFO_WUNLOCK(&V_ripcbinfo);
577		free(filter, M_PCB);
578		return (error);
579	}
580	inp = (struct inpcb *)so->so_pcb;
581	INP_INFO_WUNLOCK(&V_ripcbinfo);
582	inp->inp_vflag |= INP_IPV6;
583	inp->in6p_ip6_nxt = (long)proto;
584	inp->in6p_hops = -1;	/* use kernel default */
585	inp->in6p_cksum = -1;
586	inp->in6p_icmp6filt = filter;
587	ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
588	INP_WUNLOCK(inp);
589	return (0);
590}
591
592static void
593rip6_detach(struct socket *so)
594{
595	INIT_VNET_INET(so->so_vnet);
596	struct inpcb *inp;
597
598	inp = sotoinpcb(so);
599	KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
600
601	if (so == ip6_mrouter && ip6_mrouter_done)
602		ip6_mrouter_done();
603	/* xxx: RSVP */
604	INP_INFO_WLOCK(&V_ripcbinfo);
605	INP_WLOCK(inp);
606	free(inp->in6p_icmp6filt, M_PCB);
607	in6_pcbdetach(inp);
608	in6_pcbfree(inp);
609	INP_INFO_WUNLOCK(&V_ripcbinfo);
610}
611
612/* XXXRW: This can't ever be called. */
613static void
614rip6_abort(struct socket *so)
615{
616	struct inpcb *inp;
617
618	inp = sotoinpcb(so);
619	KASSERT(inp != NULL, ("rip6_abort: inp == NULL"));
620
621	soisdisconnected(so);
622}
623
624static void
625rip6_close(struct socket *so)
626{
627	struct inpcb *inp;
628
629	inp = sotoinpcb(so);
630	KASSERT(inp != NULL, ("rip6_close: inp == NULL"));
631
632	soisdisconnected(so);
633}
634
635static int
636rip6_disconnect(struct socket *so)
637{
638	struct inpcb *inp;
639
640	inp = sotoinpcb(so);
641	KASSERT(inp != NULL, ("rip6_disconnect: inp == NULL"));
642
643	if ((so->so_state & SS_ISCONNECTED) == 0)
644		return (ENOTCONN);
645	inp->in6p_faddr = in6addr_any;
646	rip6_abort(so);
647	return (0);
648}
649
650static int
651rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
652{
653	INIT_VNET_NET(so->so_vnet);
654	INIT_VNET_INET(so->so_vnet);
655	INIT_VNET_INET6(so->so_vnet);
656	struct inpcb *inp;
657	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
658	struct ifaddr *ia = NULL;
659	int error = 0;
660
661	inp = sotoinpcb(so);
662	KASSERT(inp != NULL, ("rip6_bind: inp == NULL"));
663
664	if (nam->sa_len != sizeof(*addr))
665		return (EINVAL);
666	if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
667		return (EADDRNOTAVAIL);
668	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
669		return (error);
670
671	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
672	    (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
673		return (EADDRNOTAVAIL);
674	if (ia &&
675	    ((struct in6_ifaddr *)ia)->ia6_flags &
676	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
677	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
678		return (EADDRNOTAVAIL);
679	}
680	INP_INFO_WLOCK(&V_ripcbinfo);
681	INP_WLOCK(inp);
682	inp->in6p_laddr = addr->sin6_addr;
683	INP_WUNLOCK(inp);
684	INP_INFO_WUNLOCK(&V_ripcbinfo);
685	return (0);
686}
687
688static int
689rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
690{
691	INIT_VNET_NET(so->so_vnet);
692	INIT_VNET_INET(so->so_vnet);
693	INIT_VNET_INET6(so->so_vnet);
694	struct inpcb *inp;
695	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
696	struct in6_addr *in6a = NULL;
697	struct ifnet *ifp = NULL;
698	int error = 0, scope_ambiguous = 0;
699
700	inp = sotoinpcb(so);
701	KASSERT(inp != NULL, ("rip6_connect: inp == NULL"));
702
703	if (nam->sa_len != sizeof(*addr))
704		return (EINVAL);
705	if (TAILQ_EMPTY(&V_ifnet))
706		return (EADDRNOTAVAIL);
707	if (addr->sin6_family != AF_INET6)
708		return (EAFNOSUPPORT);
709
710	/*
711	 * Application should provide a proper zone ID or the use of default
712	 * zone IDs should be enabled.  Unfortunately, some applications do
713	 * not behave as it should, so we need a workaround.  Even if an
714	 * appropriate ID is not determined, we'll see if we can determine
715	 * the outgoing interface.  If we can, determine the zone ID based on
716	 * the interface below.
717	 */
718	if (addr->sin6_scope_id == 0 && !V_ip6_use_defzone)
719		scope_ambiguous = 1;
720	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
721		return (error);
722
723	INP_INFO_WLOCK(&V_ripcbinfo);
724	INP_WLOCK(inp);
725	/* Source address selection. XXX: need pcblookup? */
726	in6a = in6_selectsrc(addr, inp->in6p_outputopts,
727			     inp, NULL, so->so_cred,
728			     &ifp, &error);
729	if (in6a == NULL) {
730		INP_WUNLOCK(inp);
731		INP_INFO_WUNLOCK(&V_ripcbinfo);
732		return (error ? error : EADDRNOTAVAIL);
733	}
734
735	/* XXX: see above */
736	if (ifp && scope_ambiguous &&
737	    (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
738		INP_WUNLOCK(inp);
739		INP_INFO_WUNLOCK(&V_ripcbinfo);
740		return (error);
741	}
742	inp->in6p_faddr = addr->sin6_addr;
743	inp->in6p_laddr = *in6a;
744	soisconnected(so);
745	INP_WUNLOCK(inp);
746	INP_INFO_WUNLOCK(&V_ripcbinfo);
747	return (0);
748}
749
750static int
751rip6_shutdown(struct socket *so)
752{
753	struct inpcb *inp;
754
755	inp = sotoinpcb(so);
756	KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL"));
757
758	INP_WLOCK(inp);
759	socantsendmore(so);
760	INP_WUNLOCK(inp);
761	return (0);
762}
763
764static int
765rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
766    struct mbuf *control, struct thread *td)
767{
768	INIT_VNET_INET(so->so_vnet);
769	struct inpcb *inp;
770	struct sockaddr_in6 tmp;
771	struct sockaddr_in6 *dst;
772	int ret;
773
774	inp = sotoinpcb(so);
775	KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
776
777	/* Always copy sockaddr to avoid overwrites. */
778	/* Unlocked read. */
779	if (so->so_state & SS_ISCONNECTED) {
780		if (nam) {
781			m_freem(m);
782			return (EISCONN);
783		}
784		/* XXX */
785		bzero(&tmp, sizeof(tmp));
786		tmp.sin6_family = AF_INET6;
787		tmp.sin6_len = sizeof(struct sockaddr_in6);
788		INP_RLOCK(inp);
789		bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
790		    sizeof(struct in6_addr));
791		INP_RUNLOCK(inp);
792		dst = &tmp;
793	} else {
794		if (nam == NULL) {
795			m_freem(m);
796			return (ENOTCONN);
797		}
798		if (nam->sa_len != sizeof(struct sockaddr_in6)) {
799			m_freem(m);
800			return (EINVAL);
801		}
802		tmp = *(struct sockaddr_in6 *)nam;
803		dst = &tmp;
804
805		if (dst->sin6_family == AF_UNSPEC) {
806			/*
807			 * XXX: we allow this case for backward
808			 * compatibility to buggy applications that
809			 * rely on old (and wrong) kernel behavior.
810			 */
811			log(LOG_INFO, "rip6 SEND: address family is "
812			    "unspec. Assume AF_INET6\n");
813			dst->sin6_family = AF_INET6;
814		} else if (dst->sin6_family != AF_INET6) {
815			m_freem(m);
816			return(EAFNOSUPPORT);
817		}
818	}
819	ret = rip6_output(m, so, dst, control);
820	return (ret);
821}
822
823struct pr_usrreqs rip6_usrreqs = {
824	.pru_abort =		rip6_abort,
825	.pru_attach =		rip6_attach,
826	.pru_bind =		rip6_bind,
827	.pru_connect =		rip6_connect,
828	.pru_control =		in6_control,
829	.pru_detach =		rip6_detach,
830	.pru_disconnect =	rip6_disconnect,
831	.pru_peeraddr =		in6_getpeeraddr,
832	.pru_send =		rip6_send,
833	.pru_shutdown =		rip6_shutdown,
834	.pru_sockaddr =		in6_getsockaddr,
835	.pru_close =		rip6_close,
836};
837