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