raw_ip6.c revision 243882
1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
2853541Sshin */
2953541Sshin
3053541Sshin/*-
3153541Sshin * Copyright (c) 1982, 1986, 1988, 1993
32139826Simp *	The Regents of the University of California.
3353541Sshin * All rights reserved.
3453541Sshin *
3553541Sshin * Redistribution and use in source and binary forms, with or without
3653541Sshin * modification, are permitted provided that the following conditions
3753541Sshin * are met:
3853541Sshin * 1. Redistributions of source code must retain the above copyright
3953541Sshin *    notice, this list of conditions and the following disclaimer.
4053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
4153541Sshin *    notice, this list of conditions and the following disclaimer in the
4253541Sshin *    documentation and/or other materials provided with the distribution.
4353541Sshin * 4. Neither the name of the University nor the names of its contributors
4453541Sshin *    may be used to endorse or promote products derived from this software
4553541Sshin *    without specific prior written permission.
4653541Sshin *
4753541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5753541Sshin * SUCH DAMAGE.
5853541Sshin *
5953541Sshin *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
6053541Sshin */
6153541Sshin
6253541Sshin#include <sys/cdefs.h>
6355009Sshin__FBSDID("$FreeBSD: head/sys/netinet6/raw_ip6.c 243882 2012-12-05 08:04:20Z glebius $");
6478064Sume
6555009Sshin#include "opt_ipsec.h"
6653541Sshin#include "opt_inet6.h"
6795759Stanimura
6895759Stanimura#include <sys/param.h>
6953541Sshin#include <sys/errno.h>
7095759Stanimura#include <sys/jail.h>
71170689Srwatson#include <sys/lock.h>
7253541Sshin#include <sys/malloc.h>
7395759Stanimura#include <sys/mbuf.h>
7495759Stanimura#include <sys/priv.h>
7553541Sshin#include <sys/proc.h>
7653541Sshin#include <sys/protosw.h>
7795759Stanimura#include <sys/signalvar.h>
78148385Sume#include <sys/socket.h>
7953541Sshin#include <sys/socketvar.h>
8053541Sshin#include <sys/sx.h>
8195759Stanimura#include <sys/syslog.h>
8253541Sshin
8353541Sshin#include <net/if.h>
8453541Sshin#include <net/if_types.h>
8553541Sshin#include <net/route.h>
8653541Sshin#include <net/vnet.h>
8795759Stanimura
8895759Stanimura#include <netinet/in.h>
8962587Sitojun#include <netinet/in_var.h>
9095759Stanimura#include <netinet/in_systm.h>
9156723Sshin#include <netinet/in_pcb.h>
9253541Sshin
9395759Stanimura#include <netinet/icmp6.h>
9453541Sshin#include <netinet/ip6.h>
9595759Stanimura#include <netinet/ip_var.h>
9662587Sitojun#include <netinet6/ip6protosw.h>
9753541Sshin#include <netinet6/ip6_mroute.h>
98171167Sgnn#include <netinet6/in6_pcb.h>
99105199Ssam#include <netinet6/ip6_var.h>
100105199Ssam#include <netinet6/nd6.h>
101171167Sgnn#include <netinet6/raw_ip6.h>
102105199Ssam#include <netinet6/scope6_var.h>
10353541Sshin#include <netinet6/send.h>
10453541Sshin
10553541Sshin#ifdef IPSEC
10653541Sshin#include <netipsec/ipsec.h>
10753541Sshin#include <netipsec/ipsec6.h>
10853541Sshin#endif /* IPSEC */
10953541Sshin
11053541Sshin#include <machine/stdarg.h>
11153541Sshin
11253541Sshin#define	satosin6(sa)	((struct sockaddr_in6 *)(sa))
11353541Sshin#define	ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
11453541Sshin
11553541Sshin/*
11653541Sshin * Raw interface to IP6 protocol.
11778064Sume */
11878064Sume
11953541SshinVNET_DECLARE(struct inpcbhead, ripcb);
120166938SbmsVNET_DECLARE(struct inpcbinfo, ripcbinfo);
121166938Sbms#define	V_ripcb				VNET(ripcb)
122166948Sbms#define	V_ripcbinfo			VNET(ripcbinfo)
123166938Sbms
124166938Sbmsextern u_long	rip_sendspace;
125166938Sbmsextern u_long	rip_recvspace;
126166938Sbms
127166938SbmsVNET_DEFINE(struct rip6stat, rip6stat);
128166938Sbms
129166938Sbms/*
13053541Sshin * Hooks for multicast routing. They all default to NULL, so leave them not
13153541Sshin * initialized and rely on BSS being set to 0.
13253541Sshin */
13353541Sshin
13453541Sshin/*
135171259Sdelphij * The socket used to communicate with the multicast routing daemon.
13653541Sshin */
13753541SshinVNET_DEFINE(struct socket *, ip6_mrouter);
13853541Sshin
13953541Sshin/*
14053541Sshin * The various mrouter functions.
14178064Sume */
142121901Sumeint (*ip6_mrouter_set)(struct socket *, struct sockopt *);
14353541Sshinint (*ip6_mrouter_get)(struct socket *, struct sockopt *);
14478064Sumeint (*ip6_mrouter_done)(void);
14578064Sumeint (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
14683934Sbrooksint (*mrt6_ioctl)(u_long, caddr_t);
14778064Sume
14878064Sume/*
14978064Sume * Setup generic address and protocol structures for raw_input routine, then
15053541Sshin * pass them along with mbuf chain.
15178064Sume */
152121901Sumeint
15353541Sshinrip6_input(struct mbuf **mp, int *offp, int proto)
154132714Srwatson{
15553541Sshin	struct ifnet *ifp;
156132714Srwatson	struct mbuf *m = *mp;
157132714Srwatson	register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
158132714Srwatson	register struct inpcb *in6p;
159132714Srwatson	struct inpcb *last = 0;
16053541Sshin	struct mbuf *opts = NULL;
161132714Srwatson	struct sockaddr_in6 fromsa;
16253541Sshin
16353541Sshin	V_rip6stat.rip6s_ipackets++;
164132714Srwatson
16553541Sshin	if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
16653541Sshin		/* XXX Send icmp6 host/port unreach? */
167132714Srwatson		m_freem(m);
16853541Sshin		return (IPPROTO_DONE);
16953541Sshin	}
170132714Srwatson
17178064Sume	init_sin6(&fromsa, m); /* general init */
17278064Sume
173151459Ssuz	ifp = m->m_pkthdr.rcvif;
17478064Sume
17578064Sume	INP_INFO_RLOCK(&V_ripcbinfo);
176132714Srwatson	LIST_FOREACH(in6p, &V_ripcb, inp_list) {
17778064Sume		/* XXX inp locking */
17853541Sshin		if ((in6p->inp_vflag & INP_IPV6) == 0)
17953541Sshin			continue;
18053541Sshin		if (in6p->inp_ip_p &&
18178064Sume		    in6p->inp_ip_p != proto)
182171167Sgnn			continue;
18378064Sume		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
18478064Sume		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
18578064Sume			continue;
186125396Sume		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
18778064Sume		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
18878064Sume			continue;
189105199Ssam		if (jailed_without_vnet(in6p->inp_cred)) {
190105199Ssam			/*
191171167Sgnn			 * Allow raw socket in jail to receive multicast;
19253541Sshin			 * assume process had PRIV_NETINET_RAW at attach,
19397658Stanimura			 * and fall through into normal filter path if so.
19497658Stanimura			 */
195121674Sume			if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
19653541Sshin			    prison_check_ip6(in6p->inp_cred,
19753541Sshin			    &ip6->ip6_dst) != 0)
19853541Sshin				continue;
199121901Sume		}
20053541Sshin		if (in6p->in6p_cksum != -1) {
20153541Sshin			V_rip6stat.rip6s_isum++;
20253541Sshin			if (in6_cksum(m, proto, *offp,
20353541Sshin			    m->m_pkthdr.len - *offp)) {
20478064Sume				INP_RUNLOCK(in6p);
20597658Stanimura				V_rip6stat.rip6s_badsum++;
20653541Sshin				continue;
20753541Sshin			}
20853541Sshin		}
209132714Srwatson		INP_RLOCK(in6p);
21053541Sshin		/*
21153541Sshin		 * If this raw socket has multicast state, and we
21253541Sshin		 * have received a multicast, check if this socket
213171167Sgnn		 * should receive it, as multicast filtering is now
21478064Sume		 * the responsibility of the transport layer.
21578064Sume		 */
21678064Sume		if (in6p->in6p_moptions &&
217125396Sume		    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
21878064Sume			/*
21978064Sume			 * If the incoming datagram is for MLD, allow it
220105199Ssam			 * through unconditionally to the raw socket.
221105199Ssam			 *
222149224Ssuz			 * Use the M_RTALERT_MLD flag to check for MLD
223105199Ssam			 * traffic without having to inspect the mbuf chain
224171167Sgnn			 * more deeply, as all MLDv1/v2 host messages MUST
22553541Sshin			 * contain the Router Alert option.
22697658Stanimura			 *
22797658Stanimura			 * In the case of MLDv1, we may not have explicitly
228121674Sume			 * joined the group, and may have set IFF_ALLMULTI
22953541Sshin			 * on the interface. im6o_mc_filter() may discard
23053541Sshin			 * control traffic we actually need to see.
23153541Sshin			 *
232121901Sume			 * Userland multicast routing daemons should continue
23353541Sshin			 * filter the control traffic appropriately.
23453541Sshin			 */
23553541Sshin			int blocked;
23678064Sume
23797658Stanimura			blocked = MCAST_PASS;
23853541Sshin			if ((m->m_flags & M_RTALERT_MLD) == 0) {
239132714Srwatson				struct sockaddr_in6 mcaddr;
24053541Sshin
24178064Sume				bzero(&mcaddr, sizeof(struct sockaddr_in6));
24278064Sume				mcaddr.sin6_len = sizeof(struct sockaddr_in6);
24378064Sume				mcaddr.sin6_family = AF_INET6;
24453541Sshin				mcaddr.sin6_addr = ip6->ip6_dst;
24553541Sshin
24653541Sshin				blocked = im6o_mc_filter(in6p->in6p_moptions,
24753541Sshin				    ifp,
24853541Sshin				    (struct sockaddr *)&mcaddr,
24953541Sshin				    (struct sockaddr *)&fromsa);
25053541Sshin			}
25153541Sshin			if (blocked != MCAST_PASS) {
25253541Sshin				IP6STAT_INC(ip6s_notmember);
25353541Sshin				INP_RUNLOCK(in6p);
254134655Srwatson				continue;
25553541Sshin			}
25653541Sshin		}
25753541Sshin		if (last != NULL) {
25862587Sitojun			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
259171259Sdelphij
26062587Sitojun#ifdef IPSEC
26162587Sitojun			/*
26262587Sitojun			 * Check AH/ESP integrity.
26362587Sitojun			 */
26478064Sume			if (n && ipsec6_in_reject(n, last)) {
26578064Sume				m_freem(n);
266125776Sume				V_ipsec6stat.in_polvio++;
26798211Shsu				/* Do not inject data into pcb. */
26862587Sitojun			} else
26962587Sitojun#endif /* IPSEC */
27062587Sitojun			if (n) {
27162587Sitojun				if (last->inp_flags & INP_CONTROLOPTS ||
27262587Sitojun				    last->inp_socket->so_options & SO_TIMESTAMP)
27362587Sitojun					ip6_savecontrol(last, n, &opts);
27462587Sitojun				/* strip intermediate headers */
27562587Sitojun				m_adj(n, *offp);
27662587Sitojun				if (sbappendaddr(&last->inp_socket->so_rcv,
27762587Sitojun						(struct sockaddr *)&fromsa,
27862587Sitojun						 n, opts) == 0) {
27962587Sitojun					m_freem(n);
28062587Sitojun					if (opts)
28162587Sitojun						m_freem(opts);
28262587Sitojun					V_rip6stat.rip6s_fullsock++;
28362587Sitojun				} else
28478064Sume					sorwakeup(last->inp_socket);
28562587Sitojun				opts = NULL;
28662587Sitojun			}
28762587Sitojun			INP_RUNLOCK(last);
288125776Sume		}
28978064Sume		last = in6p;
29062587Sitojun	}
29162587Sitojun	INP_INFO_RUNLOCK(&V_ripcbinfo);
29262587Sitojun#ifdef IPSEC
293125776Sume	/*
29478064Sume	 * Check AH/ESP integrity.
29562587Sitojun	 */
29662587Sitojun	if ((last != NULL) && ipsec6_in_reject(m, last)) {
297133192Srwatson		m_freem(m);
298133192Srwatson		V_ipsec6stat.in_polvio++;
299125776Sume		V_ip6stat.ip6s_delivered--;
30062587Sitojun		/* Do not inject data into pcb. */
30162587Sitojun		INP_RUNLOCK(last);
30253541Sshin	} else
30353541Sshin#endif /* IPSEC */
30453541Sshin	if (last != NULL) {
30553541Sshin		if (last->inp_flags & INP_CONTROLOPTS ||
30653541Sshin		    last->inp_socket->so_options & SO_TIMESTAMP)
30753541Sshin			ip6_savecontrol(last, m, &opts);
30853541Sshin		/* Strip intermediate headers. */
30953541Sshin		m_adj(m, *offp);
31053541Sshin		if (sbappendaddr(&last->inp_socket->so_rcv,
31153541Sshin		    (struct sockaddr *)&fromsa, m, opts) == 0) {
31253541Sshin			m_freem(m);
31353541Sshin			if (opts)
31453541Sshin				m_freem(opts);
315120941Sume			V_rip6stat.rip6s_fullsock++;
31653541Sshin		} else
31753541Sshin			sorwakeup(last->inp_socket);
31853541Sshin		INP_RUNLOCK(last);
31953541Sshin	} else {
32053541Sshin		V_rip6stat.rip6s_nosock++;
32153541Sshin		if (m->m_flags & M_MCAST)
32253541Sshin			V_rip6stat.rip6s_nosockmcast++;
323148247Sume		if (proto == IPPROTO_NONE)
32453541Sshin			m_freem(m);
32553541Sshin		else {
32653541Sshin			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
327148385Sume			icmp6_error(m, ICMP6_PARAM_PROB,
328121472Sume			    ICMP6_PARAMPROB_NEXTHEADER,
32953541Sshin			    prvnxtp - mtod(m, char *));
33053541Sshin		}
33153541Sshin		V_ip6stat.ip6s_delivered--;
33253541Sshin	}
33353541Sshin	return (IPPROTO_DONE);
33453541Sshin}
33553541Sshin
33653541Sshinvoid
33753541Sshinrip6_ctlinput(int cmd, struct sockaddr *sa, void *d)
338132714Srwatson{
33953541Sshin	struct ip6_hdr *ip6;
34053541Sshin	struct mbuf *m;
341170587Srwatson	int off = 0;
34253541Sshin	struct ip6ctlparam *ip6cp = NULL;
34353541Sshin	const struct sockaddr_in6 *sa6_src = NULL;
34453541Sshin	void *cmdarg;
345148242Sume	struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
346148250Sume
347121472Sume	if (sa->sa_family != AF_INET6 ||
34853541Sshin	    sa->sa_len != sizeof(struct sockaddr_in6))
349121472Sume		return;
350148247Sume
351148247Sume	if ((unsigned)cmd >= PRC_NCMDS)
352148247Sume		return;
35353541Sshin	if (PRC_IS_REDIRECT(cmd))
35453541Sshin		notify = in6_rtchange, d = NULL;
355148385Sume	else if (cmd == PRC_HOSTDEAD)
356148385Sume		d = NULL;
357148385Sume	else if (inet6ctlerrmap[cmd] == 0)
358148385Sume		return;
359148385Sume
360148385Sume	/*
361148385Sume	 * If the parameter is from icmp6, decode it.
362148385Sume	 */
363148385Sume	if (d != NULL) {
364148385Sume		ip6cp = (struct ip6ctlparam *)d;
365148385Sume		m = ip6cp->ip6c_m;
36653541Sshin		ip6 = ip6cp->ip6c_ip6;
36753541Sshin		off = ip6cp->ip6c_off;
36853541Sshin		cmdarg = ip6cp->ip6c_cmdarg;
36953541Sshin		sa6_src = ip6cp->ip6c_src;
37053541Sshin	} else {
37153541Sshin		m = NULL;
37253541Sshin		ip6 = NULL;
37353541Sshin		cmdarg = NULL;
37453541Sshin		sa6_src = &sa6_any;
37553541Sshin	}
37653541Sshin
37753541Sshin	(void) in6_pcbnotify(&V_ripcbinfo, sa, 0,
37853541Sshin	    (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
37953541Sshin}
38053541Sshin
381133592Srwatson/*
382133592Srwatson * Generate IPv6 header and pass packet to ip6_output.  Tack on options user
383133592Srwatson * may have setup with control call.
384133592Srwatson */
385133592Srwatsonint
38653541Sshin#if __STDC__
38753541Sshinrip6_output(struct mbuf *m, ...)
38853541Sshin#else
38953541Sshinrip6_output(m, va_alist)
39053541Sshin	struct mbuf *m;
391148247Sume	va_dcl
392148385Sume#endif
393121472Sume{
394121472Sume	struct mbuf *control;
395121472Sume	struct m_tag *mtag;
39653541Sshin	struct socket *so;
397121472Sume	struct sockaddr_in6 *dstsock;
398148385Sume	struct in6_addr *dst;
399148385Sume	struct ip6_hdr *ip6;
400148385Sume	struct inpcb *in6p;
401148385Sume	u_int	plen = m->m_pkthdr.len;
402148385Sume	int error = 0;
403148385Sume	struct ip6_pktopts opt, *optp;
404148385Sume	struct ifnet *oifp = NULL;
405148385Sume	int type = 0, code = 0;		/* for ICMPv6 output statistics only */
406148385Sume	int scope_ambiguous = 0;
407148385Sume	int use_defzone = 0;
408148385Sume	struct in6_addr in6a;
409148385Sume	va_list ap;
410148385Sume
411148385Sume	va_start(ap, m);
412148385Sume	so = va_arg(ap, struct socket *);
413148385Sume	dstsock = va_arg(ap, struct sockaddr_in6 *);
414148385Sume	control = va_arg(ap, struct mbuf *);
41555009Sshin	va_end(ap);
41655009Sshin
41755009Sshin	in6p = sotoinpcb(so);
41855009Sshin	INP_WLOCK(in6p);
41953541Sshin
42053541Sshin	dst = &dstsock->sin6_addr;
42153541Sshin	if (control != NULL) {
42253541Sshin		if ((error = ip6_setpktopts(control, &opt,
42353541Sshin		    in6p->in6p_outputopts, so->so_cred,
42453541Sshin		    so->so_proto->pr_protocol)) != 0) {
42553541Sshin			goto bad;
42653541Sshin		}
42753541Sshin		optp = &opt;
42853541Sshin	} else
42953541Sshin		optp = in6p->in6p_outputopts;
43053541Sshin
43153541Sshin	/*
43253541Sshin	 * Check and convert scope zone ID into internal form.
43353541Sshin	 *
43453541Sshin	 * XXX: we may still need to determine the zone later.
43553541Sshin	 */
43653541Sshin	if (!(so->so_state & SS_ISCONNECTED)) {
43753541Sshin		if (!optp || !optp->ip6po_pktinfo ||
43853541Sshin		    !optp->ip6po_pktinfo->ipi6_ifindex)
43953541Sshin			use_defzone = V_ip6_use_defzone;
44053541Sshin		if (dstsock->sin6_scope_id == 0 && !use_defzone)
44153541Sshin			scope_ambiguous = 1;
44253541Sshin		if ((error = sa6_embedscope(dstsock, use_defzone)) != 0)
44353541Sshin			goto bad;
44453541Sshin	}
44553541Sshin
44653541Sshin	/*
44753541Sshin	 * For an ICMPv6 packet, we should know its type and code to update
44853541Sshin	 * statistics.
44953541Sshin	 */
45053541Sshin	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
45153541Sshin		struct icmp6_hdr *icmp6;
452148247Sume		if (m->m_len < sizeof(struct icmp6_hdr) &&
45353541Sshin		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
45453541Sshin			error = ENOBUFS;
45553541Sshin			goto bad;
45653541Sshin		}
45778064Sume		icmp6 = mtod(m, struct icmp6_hdr *);
45878064Sume		type = icmp6->icmp6_type;
45953541Sshin		code = icmp6->icmp6_code;
46053541Sshin	}
46153541Sshin
46253541Sshin	M_PREPEND(m, sizeof(*ip6), M_NOWAIT);
46353541Sshin	if (m == NULL) {
46453541Sshin		error = ENOBUFS;
46553541Sshin		goto bad;
46653541Sshin	}
46778064Sume	ip6 = mtod(m, struct ip6_hdr *);
468148247Sume
46953541Sshin	/*
47078064Sume	 * Source address selection.
471132714Srwatson	 */
472120856Sume	error = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
47353541Sshin	    &oifp, &in6a);
47453541Sshin	if (error)
47553541Sshin		goto bad;
47653541Sshin	error = prison_check_ip6(in6p->inp_cred, &in6a);
47753541Sshin	if (error != 0)
47853541Sshin		goto bad;
479171259Sdelphij	ip6->ip6_src = in6a;
48053541Sshin
48153541Sshin	if (oifp && scope_ambiguous) {
48253541Sshin		/*
48353541Sshin		 * Application should provide a proper zone ID or the use of
48453541Sshin		 * default zone IDs should be enabled.  Unfortunately, some
48553541Sshin		 * applications do not behave as it should, so we need a
48653541Sshin		 * workaround.  Even if an appropriate ID is not determined
48753541Sshin		 * (when it's required), if we can determine the outgoing
488120856Sume		 * interface. determine the zone ID based on the interface.
48953541Sshin		 */
49053541Sshin		error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
49153541Sshin		if (error != 0)
49253541Sshin			goto bad;
49353541Sshin	}
49453541Sshin	ip6->ip6_dst = dstsock->sin6_addr;
49553541Sshin
49653541Sshin	/*
49756723Sshin	 * Fill in the rest of the IPv6 header fields.
49856723Sshin	 */
49956723Sshin	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
50056723Sshin	    (in6p->inp_flow & IPV6_FLOWINFO_MASK);
50156723Sshin	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
50256723Sshin	    (IPV6_VERSION & IPV6_VERSION_MASK);
50356723Sshin
504166938Sbms	/*
505166938Sbms	 * ip6_plen will be filled in ip6_output, so not fill it here.
50656723Sshin	 */
507121578Sume	ip6->ip6_nxt = in6p->inp_ip_p;
508121578Sume	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
509121578Sume
51053541Sshin	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
51153541Sshin	    in6p->in6p_cksum != -1) {
51253541Sshin		struct mbuf *n;
51353541Sshin		int off;
51453541Sshin		u_int16_t *p;
51553541Sshin
51653541Sshin		/* Compute checksum. */
51753541Sshin		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
51856723Sshin			off = offsetof(struct icmp6_hdr, icmp6_cksum);
51956723Sshin		else
52056723Sshin			off = in6p->in6p_cksum;
52156723Sshin		if (plen < off + 1) {
52256723Sshin			error = EINVAL;
52356723Sshin			goto bad;
52456723Sshin		}
525166938Sbms		off += sizeof(struct ip6_hdr);
526166938Sbms
52756723Sshin		n = m;
528121578Sume		while (n && n->m_len <= off) {
529121578Sume			off -= n->m_len;
530121578Sume			n = n->m_next;
53153541Sshin		}
53253541Sshin		if (!n)
53353541Sshin			goto bad;
53453541Sshin		p = (u_int16_t *)(mtod(n, caddr_t) + off);
53553541Sshin		*p = 0;
53653541Sshin		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
53753541Sshin	}
53853541Sshin
53953541Sshin	/*
54053541Sshin	 * Send RA/RS messages to user land for protection, before sending
54153541Sshin	 * them to rtadvd/rtsol.
54283366Sjulian	 */
54353541Sshin	if ((send_sendso_input_hook != NULL) &&
54453541Sshin	    so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
545144261Ssam		switch (type) {
546157676Srwatson		case ND_ROUTER_ADVERT:
54753541Sshin		case ND_ROUTER_SOLICIT:
54853541Sshin			mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
549157374Srwatson				sizeof(unsigned short), M_NOWAIT);
550157374Srwatson			if (mtag == NULL)
55153541Sshin				goto bad;
55255009Sshin			m_tag_prepend(m, mtag);
553157374Srwatson		}
55455009Sshin	}
555144261Ssam
556144261Ssam	error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p);
557157374Srwatson	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
558144261Ssam		if (oifp)
559157374Srwatson			icmp6_ifoutstat_inc(oifp, type, code);
560160491Sups		ICMP6STAT_INC(icp6s_outhist[type]);
561132714Srwatson	} else
562132714Srwatson		V_rip6stat.rip6s_opackets++;
563144261Ssam
56453541Sshin	goto freectl;
565132714Srwatson
56653541Sshin bad:
567132714Srwatson	if (m)
56853541Sshin		m_freem(m);
56953541Sshin
57053541Sshin freectl:
57153541Sshin	if (control != NULL) {
572144261Ssam		ip6_clearpktopts(&opt, -1);
57353541Sshin		m_freem(control);
574132714Srwatson	}
57553541Sshin	INP_WUNLOCK(in6p);
57653541Sshin	return (error);
57753541Sshin}
578157370Srwatson
57953541Sshin/*
58053541Sshin * Raw IPv6 socket option processing.
58153541Sshin */
58253541Sshinint
58353541Sshinrip6_ctloutput(struct socket *so, struct sockopt *sopt)
584157374Srwatson{
585160549Srwatson	struct inpcb *inp;
586166938Sbms	int error;
587166938Sbms
58853541Sshin	if (sopt->sopt_level == IPPROTO_ICMPV6)
589160549Srwatson		/*
590160549Srwatson		 * XXX: is it better to call icmp6_ctloutput() directly
59153541Sshin		 * from protosw?
59253541Sshin		 */
59353541Sshin		return (icmp6_ctloutput(so, sopt));
59453541Sshin	else if (sopt->sopt_level != IPPROTO_IPV6) {
59553541Sshin		if (sopt->sopt_level == SOL_SOCKET &&
596157374Srwatson		    sopt->sopt_name == SO_SETFIB) {
597132714Srwatson			inp = sotoinpcb(so);
59853541Sshin			INP_WLOCK(inp);
59953541Sshin			inp->inp_inc.inc_fibnum = so->so_fibnum;
600160549Srwatson			INP_WUNLOCK(inp);
601157366Srwatson			return (0);
60253541Sshin		}
60353541Sshin		return (EINVAL);
604160549Srwatson	}
605160549Srwatson
606160549Srwatson	error = 0;
607160549Srwatson
608160549Srwatson	switch (sopt->sopt_dir) {
60953541Sshin	case SOPT_GET:
61053541Sshin		switch (sopt->sopt_name) {
61153541Sshin		case MRT6_INIT:
612160549Srwatson		case MRT6_DONE:
613160549Srwatson		case MRT6_ADD_MIF:
614160549Srwatson		case MRT6_DEL_MIF:
615160549Srwatson		case MRT6_ADD_MFC:
616160549Srwatson		case MRT6_DEL_MFC:
617160549Srwatson		case MRT6_PIM:
618160549Srwatson			error = ip6_mrouter_get ?  ip6_mrouter_get(so, sopt) :
619160549Srwatson			    EOPNOTSUPP;
620160549Srwatson			break;
621160549Srwatson		case IPV6_CHECKSUM:
622160549Srwatson			error = ip6_raw_ctloutput(so, sopt);
62353541Sshin			break;
62453541Sshin		default:
62553541Sshin			error = ip6_ctloutput(so, sopt);
62653541Sshin			break;
62753541Sshin		}
62897658Stanimura		break;
62953541Sshin
63053541Sshin	case SOPT_SET:
631157366Srwatson		switch (sopt->sopt_name) {
632157374Srwatson		case MRT6_INIT:
63353541Sshin		case MRT6_DONE:
63453541Sshin		case MRT6_ADD_MIF:
63553541Sshin		case MRT6_DEL_MIF:
63683366Sjulian		case MRT6_ADD_MFC:
63753541Sshin		case MRT6_DEL_MFC:
63853541Sshin		case MRT6_PIM:
63953541Sshin			error = ip6_mrouter_set ?  ip6_mrouter_set(so, sopt) :
64053541Sshin			    EOPNOTSUPP;
641148385Sume			break;
64253541Sshin		case IPV6_CHECKSUM:
643157374Srwatson			error = ip6_raw_ctloutput(so, sopt);
64453541Sshin			break;
64553541Sshin		default:
64653541Sshin			error = ip6_ctloutput(so, sopt);
64753541Sshin			break;
648148385Sume		}
649148385Sume		break;
650148385Sume	}
65153541Sshin
65253541Sshin	return (error);
65353541Sshin}
65453541Sshin
65553541Sshinstatic int
65653541Sshinrip6_attach(struct socket *so, int proto, struct thread *td)
65753541Sshin{
658120856Sume	struct inpcb *inp;
65953541Sshin	struct icmp6_filter *filter;
660132714Srwatson	int error;
661132714Srwatson
66253541Sshin	inp = sotoinpcb(so);
663132714Srwatson	KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
664132714Srwatson
66553541Sshin	error = priv_check(td, PRIV_NETINET_RAW);
66653541Sshin	if (error)
66753541Sshin		return (error);
66853541Sshin	error = soreserve(so, rip_sendspace, rip_recvspace);
66983366Sjulian	if (error)
67053541Sshin		return (error);
67153541Sshin	filter = malloc(sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
67253541Sshin	if (filter == NULL)
67353541Sshin		return (ENOMEM);
674148385Sume	INP_INFO_WLOCK(&V_ripcbinfo);
675148385Sume	error = in_pcballoc(so, &V_ripcbinfo);
67653541Sshin	if (error) {
677157374Srwatson		INP_INFO_WUNLOCK(&V_ripcbinfo);
67853541Sshin		free(filter, M_PCB);
67953541Sshin		return (error);
68053541Sshin	}
68153541Sshin	inp = (struct inpcb *)so->so_pcb;
68253541Sshin	INP_INFO_WUNLOCK(&V_ripcbinfo);
68353541Sshin	inp->inp_vflag |= INP_IPV6;
684148385Sume	inp->inp_ip_p = (long)proto;
685148385Sume	inp->in6p_hops = -1;	/* use kernel default */
686148385Sume	inp->in6p_cksum = -1;
687148385Sume	inp->in6p_icmp6filt = filter;
688148385Sume	ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
689148385Sume	INP_WUNLOCK(inp);
690148385Sume	return (0);
691148385Sume}
692148385Sume
693148385Sumestatic void
694148385Sumerip6_detach(struct socket *so)
695148385Sume{
696148385Sume	struct inpcb *inp;
697148385Sume
698132714Srwatson	inp = sotoinpcb(so);
699132714Srwatson	KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
70053541Sshin
70153541Sshin	if (so == V_ip6_mrouter && ip6_mrouter_done)
702122927Sandre		ip6_mrouter_done();
703148385Sume	/* xxx: RSVP */
704132714Srwatson	INP_INFO_WLOCK(&V_ripcbinfo);
705132714Srwatson	INP_WLOCK(inp);
706132714Srwatson	free(inp->in6p_icmp6filt, M_PCB);
70753541Sshin	in_pcbdetach(inp);
708132714Srwatson	in_pcbfree(inp);
709148385Sume	INP_INFO_WUNLOCK(&V_ripcbinfo);
710148385Sume}
711148385Sume
712148385Sume/* XXXRW: This can't ever be called. */
713148385Sumestatic void
714148385Sumerip6_abort(struct socket *so)
715148385Sume{
716148385Sume	struct inpcb *inp;
717148385Sume
71853541Sshin	inp = sotoinpcb(so);
71953541Sshin	KASSERT(inp != NULL, ("rip6_abort: inp == NULL"));
720132714Srwatson
721132714Srwatson	soisdisconnected(so);
72253541Sshin}
72353541Sshin
72453541Sshinstatic void
72553541Sshinrip6_close(struct socket *so)
72653541Sshin{
72753541Sshin	struct inpcb *inp;
728132714Srwatson
729132714Srwatson	inp = sotoinpcb(so);
730132714Srwatson	KASSERT(inp != NULL, ("rip6_close: inp == NULL"));
731157374Srwatson
732132714Srwatson	soisdisconnected(so);
73353541Sshin}
734132714Srwatson
73553541Sshinstatic int
73653541Sshinrip6_disconnect(struct socket *so)
73753541Sshin{
73853541Sshin	struct inpcb *inp;
73953541Sshin
740171260Sdelphij	inp = sotoinpcb(so);
74153541Sshin	KASSERT(inp != NULL, ("rip6_disconnect: inp == NULL"));
74253541Sshin
74353541Sshin	if ((so->so_state & SS_ISCONNECTED) == 0)
74453541Sshin		return (ENOTCONN);
745132714Srwatson	inp->in6p_faddr = in6addr_any;
74653541Sshin	rip6_abort(so);
747157374Srwatson	return (0);
748132714Srwatson}
74962587Sitojun
750132714Srwatsonstatic int
75153541Sshinrip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
75253541Sshin{
753132714Srwatson	struct inpcb *inp;
75453541Sshin	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
75553541Sshin	struct ifaddr *ifa = NULL;
75653541Sshin	int error = 0;
75753541Sshin
75853541Sshin	inp = sotoinpcb(so);
75953541Sshin	KASSERT(inp != NULL, ("rip6_bind: inp == NULL"));
76053541Sshin
76153541Sshin	if (nam->sa_len != sizeof(*addr))
76253541Sshin		return (EINVAL);
76353541Sshin	if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0)
76453541Sshin		return (error);
76553541Sshin	if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
766132714Srwatson		return (EADDRNOTAVAIL);
76753541Sshin	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
76853541Sshin		return (error);
76953541Sshin
770148385Sume	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
771148385Sume	    (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
772148385Sume		return (EADDRNOTAVAIL);
773148385Sume	if (ifa != NULL &&
774148385Sume	    ((struct in6_ifaddr *)ifa)->ia6_flags &
77562587Sitojun	    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
77662587Sitojun	     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
777148385Sume		ifa_free(ifa);
778148385Sume		return (EADDRNOTAVAIL);
779148385Sume	}
780148385Sume	if (ifa != NULL)
781148385Sume		ifa_free(ifa);
782148385Sume	INP_INFO_WLOCK(&V_ripcbinfo);
783148385Sume	INP_WLOCK(inp);
784148385Sume	inp->in6p_laddr = addr->sin6_addr;
785148385Sume	INP_WUNLOCK(inp);
786148385Sume	INP_INFO_WUNLOCK(&V_ripcbinfo);
787148385Sume	return (0);
788148385Sume}
789148385Sume
790148385Sumestatic int
791148385Sumerip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
79253541Sshin{
793132714Srwatson	struct inpcb *inp;
794132714Srwatson	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
795132714Srwatson	struct in6_addr in6a;
79653541Sshin	struct ifnet *ifp = NULL;
79753541Sshin	int error = 0, scope_ambiguous = 0;
79853541Sshin
799137386Sphk	inp = sotoinpcb(so);
800137386Sphk	KASSERT(inp != NULL, ("rip6_connect: inp == NULL"));
801137386Sphk
802137386Sphk	if (nam->sa_len != sizeof(*addr))
803137386Sphk		return (EINVAL);
804137386Sphk	if (TAILQ_EMPTY(&V_ifnet))
805137386Sphk		return (EADDRNOTAVAIL);
806169462Srwatson	if (addr->sin6_family != AF_INET6)
807137386Sphk		return (EAFNOSUPPORT);
808137386Sphk
809169462Srwatson	/*
810160549Srwatson	 * Application should provide a proper zone ID or the use of default
81153541Sshin	 * zone IDs should be enabled.  Unfortunately, some applications do
812	 * not behave as it should, so we need a workaround.  Even if an
813	 * appropriate ID is not determined, we'll see if we can determine
814	 * the outgoing interface.  If we can, determine the zone ID based on
815	 * the interface below.
816	 */
817	if (addr->sin6_scope_id == 0 && !V_ip6_use_defzone)
818		scope_ambiguous = 1;
819	if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
820		return (error);
821
822	INP_INFO_WLOCK(&V_ripcbinfo);
823	INP_WLOCK(inp);
824	/* Source address selection. XXX: need pcblookup? */
825	error = in6_selectsrc(addr, inp->in6p_outputopts,
826	    inp, NULL, so->so_cred, &ifp, &in6a);
827	if (error) {
828		INP_WUNLOCK(inp);
829		INP_INFO_WUNLOCK(&V_ripcbinfo);
830		return (error);
831	}
832
833	/* XXX: see above */
834	if (ifp && scope_ambiguous &&
835	    (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
836		INP_WUNLOCK(inp);
837		INP_INFO_WUNLOCK(&V_ripcbinfo);
838		return (error);
839	}
840	inp->in6p_faddr = addr->sin6_addr;
841	inp->in6p_laddr = in6a;
842	soisconnected(so);
843	INP_WUNLOCK(inp);
844	INP_INFO_WUNLOCK(&V_ripcbinfo);
845	return (0);
846}
847
848static int
849rip6_shutdown(struct socket *so)
850{
851	struct inpcb *inp;
852
853	inp = sotoinpcb(so);
854	KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL"));
855
856	INP_WLOCK(inp);
857	socantsendmore(so);
858	INP_WUNLOCK(inp);
859	return (0);
860}
861
862static int
863rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
864    struct mbuf *control, struct thread *td)
865{
866	struct inpcb *inp;
867	struct sockaddr_in6 tmp;
868	struct sockaddr_in6 *dst;
869	int ret;
870
871	inp = sotoinpcb(so);
872	KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
873
874	/* Always copy sockaddr to avoid overwrites. */
875	/* Unlocked read. */
876	if (so->so_state & SS_ISCONNECTED) {
877		if (nam) {
878			m_freem(m);
879			return (EISCONN);
880		}
881		/* XXX */
882		bzero(&tmp, sizeof(tmp));
883		tmp.sin6_family = AF_INET6;
884		tmp.sin6_len = sizeof(struct sockaddr_in6);
885		INP_RLOCK(inp);
886		bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
887		    sizeof(struct in6_addr));
888		INP_RUNLOCK(inp);
889		dst = &tmp;
890	} else {
891		if (nam == NULL) {
892			m_freem(m);
893			return (ENOTCONN);
894		}
895		if (nam->sa_len != sizeof(struct sockaddr_in6)) {
896			m_freem(m);
897			return (EINVAL);
898		}
899		tmp = *(struct sockaddr_in6 *)nam;
900		dst = &tmp;
901
902		if (dst->sin6_family == AF_UNSPEC) {
903			/*
904			 * XXX: we allow this case for backward
905			 * compatibility to buggy applications that
906			 * rely on old (and wrong) kernel behavior.
907			 */
908			log(LOG_INFO, "rip6 SEND: address family is "
909			    "unspec. Assume AF_INET6\n");
910			dst->sin6_family = AF_INET6;
911		} else if (dst->sin6_family != AF_INET6) {
912			m_freem(m);
913			return(EAFNOSUPPORT);
914		}
915	}
916	ret = rip6_output(m, so, dst, control);
917	return (ret);
918}
919
920struct pr_usrreqs rip6_usrreqs = {
921	.pru_abort =		rip6_abort,
922	.pru_attach =		rip6_attach,
923	.pru_bind =		rip6_bind,
924	.pru_connect =		rip6_connect,
925	.pru_control =		in6_control,
926	.pru_detach =		rip6_detach,
927	.pru_disconnect =	rip6_disconnect,
928	.pru_peeraddr =		in6_getpeeraddr,
929	.pru_send =		rip6_send,
930	.pru_shutdown =		rip6_shutdown,
931	.pru_sockaddr =		in6_getsockaddr,
932	.pru_close =		rip6_close,
933};
934