12b54eeaimp/*-
24736ccfpfg * SPDX-License-Identifier: BSD-3-Clause
34736ccfpfg *
4cad2014shin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5cad2014shin * All rights reserved.
6cad2014shin *
7cad2014shin * Redistribution and use in source and binary forms, with or without
8cad2014shin * modification, are permitted provided that the following conditions
9cad2014shin * are met:
10cad2014shin * 1. Redistributions of source code must retain the above copyright
11cad2014shin *    notice, this list of conditions and the following disclaimer.
12cad2014shin * 2. Redistributions in binary form must reproduce the above copyright
13cad2014shin *    notice, this list of conditions and the following disclaimer in the
14cad2014shin *    documentation and/or other materials provided with the distribution.
15cad2014shin * 3. Neither the name of the project nor the names of its contributors
16cad2014shin *    may be used to endorse or promote products derived from this software
17cad2014shin *    without specific prior written permission.
18cad2014shin *
19cad2014shin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20cad2014shin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21cad2014shin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22cad2014shin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23cad2014shin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24cad2014shin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25cad2014shin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26cad2014shin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27cad2014shin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28cad2014shin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29cad2014shin * SUCH DAMAGE.
30cad2014shin */
31cad2014shin
322b54eeaimp/*-
33cad2014shin * Copyright (c) 1982, 1986, 1988, 1993
346ee57a2rwatson *	The Regents of the University of California.
356ee57a2rwatson * All rights reserved.
36cad2014shin *
37cad2014shin * Redistribution and use in source and binary forms, with or without
38cad2014shin * modification, are permitted provided that the following conditions
39cad2014shin * are met:
40cad2014shin * 1. Redistributions of source code must retain the above copyright
41cad2014shin *    notice, this list of conditions and the following disclaimer.
42cad2014shin * 2. Redistributions in binary form must reproduce the above copyright
43cad2014shin *    notice, this list of conditions and the following disclaimer in the
44cad2014shin *    documentation and/or other materials provided with the distribution.
457e6cabdimp * 3. Neither the name of the University nor the names of its contributors
46cad2014shin *    may be used to endorse or promote products derived from this software
47cad2014shin *    without specific prior written permission.
48cad2014shin *
49cad2014shin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50cad2014shin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51cad2014shin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52cad2014shin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53cad2014shin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54cad2014shin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55cad2014shin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56cad2014shin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57cad2014shin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58cad2014shin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59cad2014shin * SUCH DAMAGE.
60cad2014shin *
61cad2014shin *	@(#)raw_ip.c	8.2 (Berkeley) 1/4/94
62cad2014shin */
63cad2014shin
640d684d9obrien#include <sys/cdefs.h>
650d684d9obrien__FBSDID("$FreeBSD$");
660d684d9obrien
6750ba589shin#include "opt_ipsec.h"
68832f8d2ume#include "opt_inet6.h"
6950ba589shin
70cad2014shin#include <sys/param.h>
7189ec521tanimura#include <sys/errno.h>
72d2730d5bz#include <sys/jail.h>
73e5b002aae#include <sys/kernel.h>
7489ec521tanimura#include <sys/lock.h>
75cad2014shin#include <sys/malloc.h>
76cad2014shin#include <sys/mbuf.h>
77f938c62rwatson#include <sys/priv.h>
7889ec521tanimura#include <sys/proc.h>
79cad2014shin#include <sys/protosw.h>
8089ec521tanimura#include <sys/signalvar.h>
8189ec521tanimura#include <sys/socket.h>
82cad2014shin#include <sys/socketvar.h>
8389ec521tanimura#include <sys/sx.h>
84da2cf62ume#include <sys/syslog.h>
85cad2014shin
86cad2014shin#include <net/if.h>
87ff6e113glebius#include <net/if_var.h>
88cad2014shin#include <net/if_types.h>
8989ec521tanimura#include <net/route.h>
90604d894bz#include <net/vnet.h>
91cad2014shin
92cad2014shin#include <netinet/in.h>
93cad2014shin#include <netinet/in_var.h>
94cad2014shin#include <netinet/in_systm.h>
95cad2014shin#include <netinet/in_pcb.h>
96604d894bz
97604d894bz#include <netinet/icmp6.h>
9889ec521tanimura#include <netinet/ip6.h>
99c6c2febanchie#include <netinet/ip_var.h>
10089ec521tanimura#include <netinet6/ip6protosw.h>
10189ec521tanimura#include <netinet6/ip6_mroute.h>
102cad2014shin#include <netinet6/in6_pcb.h>
10389ec521tanimura#include <netinet6/ip6_var.h>
104cad2014shin#include <netinet6/nd6.h>
10589ec521tanimura#include <netinet6/raw_ip6.h>
1065f4e854itojun#include <netinet6/scope6_var.h>
107c6c2febanchie#include <netinet6/send.h>
108cad2014shin
1090fb6ad5ae#include <netipsec/ipsec_support.h>
1100ef6c52sam
111cad2014shin#include <machine/stdarg.h>
112cad2014shin
113cad2014shin#define	satosin6(sa)	((struct sockaddr_in6 *)(sa))
114cad2014shin#define	ifatoia6(ifa)	((struct in6_ifaddr *)(ifa))
115cad2014shin
116cad2014shin/*
117cad2014shin * Raw interface to IP6 protocol.
118cad2014shin */
119cad2014shin
12057ca458rwatsonVNET_DECLARE(struct inpcbhead, ripcb);
12157ca458rwatsonVNET_DECLARE(struct inpcbinfo, ripcbinfo);
12288f8de4rwatson#define	V_ripcb				VNET(ripcb)
12388f8de4rwatson#define	V_ripcbinfo			VNET(ripcbinfo)
12457ca458rwatson
12595a15f5zecextern u_long	rip_sendspace;
12695a15f5zecextern u_long	rip_recvspace;
12795a15f5zec
128e5b002aaeVNET_PCPUSTAT_DEFINE(struct rip6stat, rip6stat);
129e5b002aaeVNET_PCPUSTAT_SYSINIT(rip6stat);
130e5b002aae
131e5b002aae#ifdef VIMAGE
132e5b002aaeVNET_PCPUSTAT_SYSUNINIT(rip6stat);
133e5b002aae#endif /* VIMAGE */
1340a90ef1bz
135cad2014shin/*
13632a7113bms * Hooks for multicast routing. They all default to NULL, so leave them not
13732a7113bms * initialized and rely on BSS being set to 0.
13832a7113bms */
13932a7113bms
14032a7113bms/*
14132a7113bms * The socket used to communicate with the multicast routing daemon.
14232a7113bms */
14357ca458rwatsonVNET_DEFINE(struct socket *, ip6_mrouter);
14432a7113bms
14532a7113bms/*
14632a7113bms * The various mrouter functions.
1473e83ac6bms */
1483e83ac6bmsint (*ip6_mrouter_set)(struct socket *, struct sockopt *);
1493e83ac6bmsint (*ip6_mrouter_get)(struct socket *, struct sockopt *);
1503e83ac6bmsint (*ip6_mrouter_done)(void);
1513e83ac6bmsint (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
1529992cf9rdivackyint (*mrt6_ioctl)(u_long, caddr_t);
1533e83ac6bms
1543e83ac6bms/*
1556ee57a2rwatson * Setup generic address and protocol structures for raw_input routine, then
1566ee57a2rwatson * pass them along with mbuf chain.
157cad2014shin */
158cad2014shinint
159e6f8b09delphijrip6_input(struct mbuf **mp, int *offp, int proto)
160cad2014shin{
16132a7113bms	struct ifnet *ifp;
162cad2014shin	struct mbuf *m = *mp;
1631901c3eemaste	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
164f66d5bcbz	struct inpcb *inp;
16512232f8pfg	struct inpcb *last = NULL;
166832f8d2ume	struct mbuf *opts = NULL;
16787ef650ume	struct sockaddr_in6 fromsa;
16861ee0e9glebius
16961ee0e9glebius	NET_EPOCH_ASSERT();
170cad2014shin
171fc84631ae	RIP6STAT_INC(rip6s_ipackets);
172832f8d2ume
173f2a480ceri	init_sin6(&fromsa, m, 0); /* general init */
174cad2014shin
17532a7113bms	ifp = m->m_pkthdr.rcvif;
17632a7113bms
177f66d5bcbz	CK_LIST_FOREACH(inp, &V_ripcb, inp_list) {
178d2730d5bz		/* XXX inp locking */
179f66d5bcbz		if ((inp->inp_vflag & INP_IPV6) == 0)
180cad2014shin			continue;
181f66d5bcbz		if (inp->inp_ip_p &&
182f66d5bcbz		    inp->inp_ip_p != proto)
1838a791bfmav			continue;
184f66d5bcbz		if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
185f66d5bcbz		    !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &ip6->ip6_dst))
1868a791bfmav			continue;
187f66d5bcbz		if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) &&
188f66d5bcbz		    !IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &ip6->ip6_src))
1898a791bfmav			continue;
19000fd7d4bz		if (last != NULL) {
19100fd7d4bz			struct mbuf *n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
19200fd7d4bz
19300fd7d4bz#if defined(IPSEC) || defined(IPSEC_SUPPORT)
19400fd7d4bz			/*
19500fd7d4bz			 * Check AH/ESP integrity.
19600fd7d4bz			 */
19700fd7d4bz			if (IPSEC_ENABLED(ipv6)) {
19800fd7d4bz				if (n != NULL &&
19900fd7d4bz				    IPSEC_CHECK_POLICY(ipv6, n, last) != 0) {
20000fd7d4bz					m_freem(n);
20100fd7d4bz					/* Do not inject data into pcb. */
20200fd7d4bz					n = NULL;
20300fd7d4bz				}
20400fd7d4bz			}
20500fd7d4bz#endif /* IPSEC */
20600fd7d4bz			if (n) {
20700fd7d4bz				if (last->inp_flags & INP_CONTROLOPTS ||
20800fd7d4bz				    last->inp_socket->so_options & SO_TIMESTAMP)
20900fd7d4bz					ip6_savecontrol(last, n, &opts);
21000fd7d4bz				/* strip intermediate headers */
21100fd7d4bz				m_adj(n, *offp);
21200fd7d4bz				if (sbappendaddr(&last->inp_socket->so_rcv,
21300fd7d4bz						(struct sockaddr *)&fromsa,
21400fd7d4bz						 n, opts) == 0) {
21500fd7d4bz					m_freem(n);
21600fd7d4bz					if (opts)
21700fd7d4bz						m_freem(opts);
21800fd7d4bz					RIP6STAT_INC(rip6s_fullsock);
21900fd7d4bz				} else
22000fd7d4bz					sorwakeup(last->inp_socket);
22100fd7d4bz				opts = NULL;
22200fd7d4bz			}
22300fd7d4bz			INP_RUNLOCK(last);
22400fd7d4bz			last = NULL;
22500fd7d4bz		}
226f66d5bcbz		INP_RLOCK(inp);
227f66d5bcbz		if (__predict_false(inp->inp_flags2 & INP_FREED))
22800fd7d4bz			goto skip_2;
229f66d5bcbz		if (jailed_without_vnet(inp->inp_cred)) {
23032a7113bms			/*
23132a7113bms			 * Allow raw socket in jail to receive multicast;
23232a7113bms			 * assume process had PRIV_NETINET_RAW at attach,
23332a7113bms			 * and fall through into normal filter path if so.
23432a7113bms			 */
23532a7113bms			if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
236f66d5bcbz			    prison_check_ip6(inp->inp_cred,
23732a7113bms			    &ip6->ip6_dst) != 0)
23800fd7d4bz				goto skip_2;
23932a7113bms		}
240f66d5bcbz		if (inp->in6p_cksum != -1) {
241fc84631ae			RIP6STAT_INC(rip6s_isum);
242f66d5bcbz			if (m->m_pkthdr.len - (*offp + inp->in6p_cksum) < 2 ||
24336983a7tuexen			    in6_cksum(m, proto, *offp,
244832f8d2ume			    m->m_pkthdr.len - *offp)) {
245fc84631ae				RIP6STAT_INC(rip6s_badsum);
246a26060atuexen				/*
247a26060atuexen				 * Drop the received message, don't send an
248a26060atuexen				 * ICMP6 message. Set proto to IPPROTO_NONE
249a26060atuexen				 * to achieve that.
250a26060atuexen				 */
251a26060atuexen				proto = IPPROTO_NONE;
25200fd7d4bz				goto skip_2;
253832f8d2ume			}
254cad2014shin		}
25532a7113bms		/*
25632a7113bms		 * If this raw socket has multicast state, and we
25732a7113bms		 * have received a multicast, check if this socket
25832a7113bms		 * should receive it, as multicast filtering is now
25932a7113bms		 * the responsibility of the transport layer.
26032a7113bms		 */
261f66d5bcbz		if (inp->in6p_moptions &&
26232a7113bms		    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
263028af3abms			/*
264028af3abms			 * If the incoming datagram is for MLD, allow it
265028af3abms			 * through unconditionally to the raw socket.
266028af3abms			 *
267028af3abms			 * Use the M_RTALERT_MLD flag to check for MLD
268028af3abms			 * traffic without having to inspect the mbuf chain
269028af3abms			 * more deeply, as all MLDv1/v2 host messages MUST
270028af3abms			 * contain the Router Alert option.
271028af3abms			 *
272028af3abms			 * In the case of MLDv1, we may not have explicitly
273028af3abms			 * joined the group, and may have set IFF_ALLMULTI
274028af3abms			 * on the interface. im6o_mc_filter() may discard
275028af3abms			 * control traffic we actually need to see.
276028af3abms			 *
277028af3abms			 * Userland multicast routing daemons should continue
278028af3abms			 * filter the control traffic appropriately.
279028af3abms			 */
28032a7113bms			int blocked;
28132a7113bms
282028af3abms			blocked = MCAST_PASS;
283028af3abms			if ((m->m_flags & M_RTALERT_MLD) == 0) {
284028af3abms				struct sockaddr_in6 mcaddr;
28532a7113bms
286028af3abms				bzero(&mcaddr, sizeof(struct sockaddr_in6));
287028af3abms				mcaddr.sin6_len = sizeof(struct sockaddr_in6);
288028af3abms				mcaddr.sin6_family = AF_INET6;
289028af3abms				mcaddr.sin6_addr = ip6->ip6_dst;
290028af3abms
291f66d5bcbz				blocked = im6o_mc_filter(inp->in6p_moptions,
292028af3abms				    ifp,
293028af3abms				    (struct sockaddr *)&mcaddr,
294028af3abms				    (struct sockaddr *)&fromsa);
295028af3abms			}
29632a7113bms			if (blocked != MCAST_PASS) {
29732a7113bms				IP6STAT_INC(ip6s_notmember);
29800fd7d4bz				goto skip_2;
299cad2014shin			}
300cad2014shin		}
301f66d5bcbz		last = inp;
30200fd7d4bz		continue;
30300fd7d4bzskip_2:
304f66d5bcbz		INP_RUNLOCK(inp);
305cad2014shin	}
3060fb6ad5ae#if defined(IPSEC) || defined(IPSEC_SUPPORT)
307832f8d2ume	/*
308832f8d2ume	 * Check AH/ESP integrity.
309832f8d2ume	 */
3100fb6ad5ae	if (IPSEC_ENABLED(ipv6) && last != NULL &&
3110fb6ad5ae	    IPSEC_CHECK_POLICY(ipv6, m, last) != 0) {
312832f8d2ume		m_freem(m);
313844d612ae		IP6STAT_DEC(ip6s_delivered);
3146ee57a2rwatson		/* Do not inject data into pcb. */
3159ee84cdrwatson		INP_RUNLOCK(last);
3160ef6c52sam	} else
317aeca69dgnn#endif /* IPSEC */
318c501489kmacy	if (last != NULL) {
319b1db56abz		if (last->inp_flags & INP_CONTROLOPTS ||
32003f6bb9bz		    last->inp_socket->so_options & SO_TIMESTAMP)
32136edae8ume			ip6_savecontrol(last, m, &opts);
3226ee57a2rwatson		/* Strip intermediate headers. */
323cad2014shin		m_adj(m, *offp);
32403f6bb9bz		if (sbappendaddr(&last->inp_socket->so_rcv,
3256ee57a2rwatson		    (struct sockaddr *)&fromsa, m, opts) == 0) {
326cad2014shin			m_freem(m);
327cad2014shin			if (opts)
328cad2014shin				m_freem(opts);
329fc84631ae			RIP6STAT_INC(rip6s_fullsock);
330e6fa9b9tanimura		} else
33103f6bb9bz			sorwakeup(last->inp_socket);
3329ee84cdrwatson		INP_RUNLOCK(last);
333cad2014shin	} else {
334fc84631ae		RIP6STAT_INC(rip6s_nosock);
335832f8d2ume		if (m->m_flags & M_MCAST)
336fc84631ae			RIP6STAT_INC(rip6s_nosockmcast);
337cad2014shin		if (proto == IPPROTO_NONE)
338cad2014shin			m_freem(m);
3398d74fbeae		else
340cad2014shin			icmp6_error(m, ICMP6_PARAM_PROB,
3416ee57a2rwatson			    ICMP6_PARAMPROB_NEXTHEADER,
3428d74fbeae			    ip6_get_prevhdr(m, *offp));
343844d612ae		IP6STAT_DEC(ip6s_delivered);
344cad2014shin	}
3456ee57a2rwatson	return (IPPROTO_DONE);
346cad2014shin}
347cad2014shin
3485f4e854itojunvoid
349e6f8b09delphijrip6_ctlinput(int cmd, struct sockaddr *sa, void *d)
3505f4e854itojun{
351832f8d2ume	struct ip6ctlparam *ip6cp = NULL;
352832f8d2ume	const struct sockaddr_in6 *sa6_src = NULL;
353f35565eume	void *cmdarg;
3547eb385cobrien	struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
3555f4e854itojun
3565f4e854itojun	if (sa->sa_family != AF_INET6 ||
3575f4e854itojun	    sa->sa_len != sizeof(struct sockaddr_in6))
3585f4e854itojun		return;
3595f4e854itojun
3605f4e854itojun	if ((unsigned)cmd >= PRC_NCMDS)
3615f4e854itojun		return;
3625f4e854itojun	if (PRC_IS_REDIRECT(cmd))
3635f4e854itojun		notify = in6_rtchange, d = NULL;
3645f4e854itojun	else if (cmd == PRC_HOSTDEAD)
3655f4e854itojun		d = NULL;
3665f4e854itojun	else if (inet6ctlerrmap[cmd] == 0)
3675f4e854itojun		return;
3685f4e854itojun
3696ee57a2rwatson	/*
3706ee57a2rwatson	 * If the parameter is from icmp6, decode it.
3716ee57a2rwatson	 */
3725f4e854itojun	if (d != NULL) {
373832f8d2ume		ip6cp = (struct ip6ctlparam *)d;
374f35565eume		cmdarg = ip6cp->ip6c_cmdarg;
375832f8d2ume		sa6_src = ip6cp->ip6c_src;
3765f4e854itojun	} else {
377f35565eume		cmdarg = NULL;
378832f8d2ume		sa6_src = &sa6_any;
3795f4e854itojun	}
3805f4e854itojun
3811021d43bz	(void) in6_pcbnotify(&V_ripcbinfo, sa, 0,
3826ee57a2rwatson	    (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
3835f4e854itojun}
3845f4e854itojun
385cad2014shin/*
3866ee57a2rwatson * Generate IPv6 header and pass packet to ip6_output.  Tack on options user
3876ee57a2rwatson * may have setup with control call.
388cad2014shin */
389cad2014shinint
3907727a3ckevlorip6_output(struct mbuf *m, struct socket *so, ...)
391cad2014shin{
3929879d0dglebius	struct epoch_tracker et;
3935f396e4ume	struct mbuf *control;
394c6c2febanchie	struct m_tag *mtag;
395cad2014shin	struct sockaddr_in6 *dstsock;
396cad2014shin	struct ip6_hdr *ip6;
397f66d5bcbz	struct inpcb *inp;
398cad2014shin	u_int	plen = m->m_pkthdr.len;
399cad2014shin	int error = 0;
4002343049ume	struct ip6_pktopts opt, *optp;
401cad2014shin	struct ifnet *oifp = NULL;
402cad2014shin	int type = 0, code = 0;		/* for ICMPv6 output statistics only */
403da2cf62ume	int scope_ambiguous = 0;
40430f327bume	int use_defzone = 0;
40521632a9melifaro	int hlim = 0;
406a883921bz	struct in6_addr in6a;
407cad2014shin	va_list ap;
408cad2014shin
4097727a3ckevlo	va_start(ap, so);
410cad2014shin	dstsock = va_arg(ap, struct sockaddr_in6 *);
411cad2014shin	control = va_arg(ap, struct mbuf *);
412cad2014shin	va_end(ap);
413cad2014shin
414f66d5bcbz	inp = sotoinpcb(so);
415f66d5bcbz	INP_WLOCK(inp);
416cad2014shin
417222f4e2kmacy	if (control != NULL) {
418166d271ume		if ((error = ip6_setpktopts(control, &opt,
419f66d5bcbz		    inp->in6p_outputopts, so->so_cred,
4201c37628bz		    so->so_proto->pr_protocol)) != 0) {
421cad2014shin			goto bad;
422881c4faume		}
4232343049ume		optp = &opt;
4242343049ume	} else
425f66d5bcbz		optp = inp->in6p_outputopts;
426cad2014shin
427cad2014shin	/*
428da2cf62ume	 * Check and convert scope zone ID into internal form.
4296ee57a2rwatson	 *
430da2cf62ume	 * XXX: we may still need to determine the zone later.
431da2cf62ume	 */
432da2cf62ume	if (!(so->so_state & SS_ISCONNECTED)) {
433a9738fbume		if (!optp || !optp->ip6po_pktinfo ||
434a9738fbume		    !optp->ip6po_pktinfo->ipi6_ifindex)
43530f327bume			use_defzone = V_ip6_use_defzone;
43630f327bume		if (dstsock->sin6_scope_id == 0 && !use_defzone)
437da2cf62ume			scope_ambiguous = 1;
43830f327bume		if ((error = sa6_embedscope(dstsock, use_defzone)) != 0)
439da2cf62ume			goto bad;
440da2cf62ume	}
441da2cf62ume
442da2cf62ume	/*
4436ee57a2rwatson	 * For an ICMPv6 packet, we should know its type and code to update
4446ee57a2rwatson	 * statistics.
445cad2014shin	 */
446cad2014shin	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
447cad2014shin		struct icmp6_hdr *icmp6;
448cad2014shin		if (m->m_len < sizeof(struct icmp6_hdr) &&
449cad2014shin		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
450cad2014shin			error = ENOBUFS;
451cad2014shin			goto bad;
452cad2014shin		}
453cad2014shin		icmp6 = mtod(m, struct icmp6_hdr *);
454cad2014shin		type = icmp6->icmp6_type;
455cad2014shin		code = icmp6->icmp6_code;
456cad2014shin	}
457cad2014shin
4588e20fa5glebius	M_PREPEND(m, sizeof(*ip6), M_NOWAIT);
459411d86frwatson	if (m == NULL) {
460411d86frwatson		error = ENOBUFS;
461411d86frwatson		goto bad;
462411d86frwatson	}
463cad2014shin	ip6 = mtod(m, struct ip6_hdr *);
464cad2014shin
465cad2014shin	/*
466cad2014shin	 * Source address selection.
467cad2014shin	 */
468f66d5bcbz	error = in6_selectsrc_socket(dstsock, optp, inp, so->so_cred,
46921632a9melifaro	    scope_ambiguous, &in6a, &hlim);
47021632a9melifaro
471a883921bz	if (error)
472881c4faume		goto bad;
473f66d5bcbz	error = prison_check_ip6(inp->inp_cred, &in6a);
47412bbe18jamie	if (error != 0)
47512bbe18jamie		goto bad;
476a883921bz	ip6->ip6_src = in6a;
477da2cf62ume
478da2cf62ume	ip6->ip6_dst = dstsock->sin6_addr;
479da2cf62ume
4806ee57a2rwatson	/*
4816ee57a2rwatson	 * Fill in the rest of the IPv6 header fields.
4826ee57a2rwatson	 */
48350ba589shin	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
484f66d5bcbz	    (inp->inp_flow & IPV6_FLOWINFO_MASK);
48550ba589shin	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
4866ee57a2rwatson	    (IPV6_VERSION & IPV6_VERSION_MASK);
4876ee57a2rwatson
4886ee57a2rwatson	/*
4896ee57a2rwatson	 * ip6_plen will be filled in ip6_output, so not fill it here.
4906ee57a2rwatson	 */
491f66d5bcbz	ip6->ip6_nxt = inp->inp_ip_p;
49221632a9melifaro	ip6->ip6_hlim = hlim;
493cad2014shin
494cad2014shin	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
495f66d5bcbz	    inp->in6p_cksum != -1) {
496cad2014shin		struct mbuf *n;
497cad2014shin		int off;
498cad2014shin		u_int16_t *p;
499cad2014shin
5006ee57a2rwatson		/* Compute checksum. */
501cad2014shin		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
502cad2014shin			off = offsetof(struct icmp6_hdr, icmp6_cksum);
503cad2014shin		else
504f66d5bcbz			off = inp->in6p_cksum;
505ac889cftuexen		if (plen < off + 2) {
506cad2014shin			error = EINVAL;
507cad2014shin			goto bad;
508cad2014shin		}
509cad2014shin		off += sizeof(struct ip6_hdr);
510cad2014shin
511cad2014shin		n = m;
512cad2014shin		while (n && n->m_len <= off) {
513cad2014shin			off -= n->m_len;
514cad2014shin			n = n->m_next;
515cad2014shin		}
516cad2014shin		if (!n)
517cad2014shin			goto bad;
518cad2014shin		p = (u_int16_t *)(mtod(n, caddr_t) + off);
519cad2014shin		*p = 0;
520cad2014shin		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
521cad2014shin	}
522cad2014shin
523c6c2febanchie	/*
524c6c2febanchie	 * Send RA/RS messages to user land for protection, before sending
525c6c2febanchie	 * them to rtadvd/rtsol.
526c6c2febanchie	 */
527c6c2febanchie	if ((send_sendso_input_hook != NULL) &&
528c6c2febanchie	    so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
529c6c2febanchie		switch (type) {
530c6c2febanchie		case ND_ROUTER_ADVERT:
531c6c2febanchie		case ND_ROUTER_SOLICIT:
532c6c2febanchie			mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
533c6c2febanchie				sizeof(unsigned short), M_NOWAIT);
534c6c2febanchie			if (mtag == NULL)
535c6c2febanchie				goto bad;
536c6c2febanchie			m_tag_prepend(m, mtag);
537c6c2febanchie		}
538c6c2febanchie	}
539c6c2febanchie
5409879d0dglebius	NET_EPOCH_ENTER(et);
541f66d5bcbz	error = ip6_output(m, optp, NULL, 0, inp->in6p_moptions, &oifp, inp);
5429879d0dglebius	NET_EPOCH_EXIT(et);
543cad2014shin	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
544cad2014shin		if (oifp)
545cad2014shin			icmp6_ifoutstat_inc(oifp, type, code);
5464801e9arwatson		ICMP6STAT_INC(icp6s_outhist[type]);
547832f8d2ume	} else
548fc84631ae		RIP6STAT_INC(rip6s_opackets);
549cad2014shin
550cad2014shin	goto freectl;
551cad2014shin
552cad2014shin bad:
553cad2014shin	if (m)
554cad2014shin		m_freem(m);
555cad2014shin
556cad2014shin freectl:
557222f4e2kmacy	if (control != NULL) {
5582343049ume		ip6_clearpktopts(&opt, -1);
559cad2014shin		m_freem(control);
560832f8d2ume	}
561f66d5bcbz	INP_WUNLOCK(inp);
5626c1377bume	return (error);
563cad2014shin}
564cad2014shin
565cad2014shin/*
566cad2014shin * Raw IPv6 socket option processing.
567cad2014shin */
568cad2014shinint
569e6f8b09delphijrip6_ctloutput(struct socket *so, struct sockopt *sopt)
570cad2014shin{
571dcdb232bz	struct inpcb *inp;
572