xref: /netbsd-src/sys/netinet6/udp6_usrreq.c (revision 5d781b6ffb671235621ca0d7453230b9969d0374)
1*5d781b6fSriastradh /* $NetBSD: udp6_usrreq.c,v 1.156 2024/10/08 02:30:05 riastradh Exp $ */
2e91c2ce8Sitojun /* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */
363ecc40cSmaxv /* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */
4cd3a345eSthorpej 
574d3c214Sitojun /*
674d3c214Sitojun  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
774d3c214Sitojun  * All rights reserved.
874d3c214Sitojun  *
974d3c214Sitojun  * Redistribution and use in source and binary forms, with or without
1074d3c214Sitojun  * modification, are permitted provided that the following conditions
1174d3c214Sitojun  * are met:
1274d3c214Sitojun  * 1. Redistributions of source code must retain the above copyright
1374d3c214Sitojun  *    notice, this list of conditions and the following disclaimer.
1474d3c214Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
1574d3c214Sitojun  *    notice, this list of conditions and the following disclaimer in the
1674d3c214Sitojun  *    documentation and/or other materials provided with the distribution.
1774d3c214Sitojun  * 3. Neither the name of the project nor the names of its contributors
1874d3c214Sitojun  *    may be used to endorse or promote products derived from this software
1974d3c214Sitojun  *    without specific prior written permission.
2074d3c214Sitojun  *
2174d3c214Sitojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2274d3c214Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2374d3c214Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2474d3c214Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2574d3c214Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2674d3c214Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2774d3c214Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2874d3c214Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2974d3c214Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3074d3c214Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3174d3c214Sitojun  * SUCH DAMAGE.
3274d3c214Sitojun  */
3374d3c214Sitojun 
3474d3c214Sitojun /*
3574d3c214Sitojun  * Copyright (c) 1982, 1986, 1989, 1993
3674d3c214Sitojun  *	The Regents of the University of California.  All rights reserved.
3774d3c214Sitojun  *
3874d3c214Sitojun  * Redistribution and use in source and binary forms, with or without
3974d3c214Sitojun  * modification, are permitted provided that the following conditions
4074d3c214Sitojun  * are met:
4174d3c214Sitojun  * 1. Redistributions of source code must retain the above copyright
4274d3c214Sitojun  *    notice, this list of conditions and the following disclaimer.
4374d3c214Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
4474d3c214Sitojun  *    notice, this list of conditions and the following disclaimer in the
4574d3c214Sitojun  *    documentation and/or other materials provided with the distribution.
46aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
4774d3c214Sitojun  *    may be used to endorse or promote products derived from this software
4874d3c214Sitojun  *    without specific prior written permission.
4974d3c214Sitojun  *
5074d3c214Sitojun  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5174d3c214Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5274d3c214Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5374d3c214Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5474d3c214Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5574d3c214Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5674d3c214Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5774d3c214Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5874d3c214Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5974d3c214Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6074d3c214Sitojun  * SUCH DAMAGE.
6174d3c214Sitojun  *
6274d3c214Sitojun  *	@(#)udp_var.h	8.1 (Berkeley) 6/10/93
6374d3c214Sitojun  */
6474d3c214Sitojun 
654f2ad952Slukem #include <sys/cdefs.h>
66*5d781b6fSriastradh __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.156 2024/10/08 02:30:05 riastradh Exp $");
675ec72efbSchristos 
681c4a50f1Spooka #ifdef _KERNEL_OPT
695ec72efbSchristos #include "opt_inet.h"
709a6de984Srmind #include "opt_inet_csum.h"
71f35c2148Sozaki-r #include "opt_ipsec.h"
722526d8f6Sknakahara #include "opt_net_mpsafe.h"
731c4a50f1Spooka #endif
74f9a7668bSthorpej 
7574d3c214Sitojun #include <sys/param.h>
7674d3c214Sitojun #include <sys/mbuf.h>
7774d3c214Sitojun #include <sys/protosw.h>
7874d3c214Sitojun #include <sys/socket.h>
7974d3c214Sitojun #include <sys/socketvar.h>
8074d3c214Sitojun #include <sys/systm.h>
8174d3c214Sitojun #include <sys/proc.h>
826d8996baSitojun #include <sys/syslog.h>
835ec72efbSchristos #include <sys/domain.h>
845f717f7cSsimonb #include <sys/sysctl.h>
8574d3c214Sitojun 
8674d3c214Sitojun #include <net/if.h>
8774d3c214Sitojun #include <net/if_types.h>
8874d3c214Sitojun 
8974d3c214Sitojun #include <netinet/in.h>
9074d3c214Sitojun #include <netinet/in_var.h>
91ea861f01Sitojun #include <netinet/in_systm.h>
929a6de984Srmind #include <netinet/in_offload.h>
93ea861f01Sitojun #include <netinet/ip.h>
94ea861f01Sitojun #include <netinet/ip_var.h>
95ea861f01Sitojun #include <netinet/in_pcb.h>
96ea861f01Sitojun #include <netinet/udp.h>
97ea861f01Sitojun #include <netinet/udp_var.h>
989a6de984Srmind #include <netinet/udp_private.h>
999a6de984Srmind 
10090736ab6Sitojun #include <netinet/ip6.h>
10190736ab6Sitojun #include <netinet/icmp6.h>
1029a6de984Srmind #include <netinet6/ip6_var.h>
1039a6de984Srmind #include <netinet6/ip6_private.h>
1049a6de984Srmind #include <netinet6/in6_pcb.h>
10574d3c214Sitojun #include <netinet6/udp6_var.h>
106c2da059bSthorpej #include <netinet6/udp6_private.h>
107ea861f01Sitojun #include <netinet6/ip6protosw.h>
1089a6de984Srmind #include <netinet6/scope6_var.h>
10974d3c214Sitojun 
110f35c2148Sozaki-r #ifdef IPSEC
111f35c2148Sozaki-r #include <netipsec/ipsec.h>
112890dda53Sknakahara #include <netipsec/esp.h>
113f35c2148Sozaki-r #ifdef INET6
114f35c2148Sozaki-r #include <netipsec/ipsec6.h>
115f35c2148Sozaki-r #endif
116d6071245Smaxv #endif
117f35c2148Sozaki-r 
11874d3c214Sitojun #include "faith.h"
1191bec764dSitojun #if defined(NFAITH) && NFAITH > 0
1201bec764dSitojun #include <net/if_faith.h>
1211bec764dSitojun #endif
12274d3c214Sitojun 
12374d3c214Sitojun /*
12478678b13Srpaulo  * UDP protocol implementation.
12574d3c214Sitojun  * Per RFC 768, August, 1980.
12674d3c214Sitojun  */
12774d3c214Sitojun 
128495906caSitojun extern struct inpcbtable udbtable;
129c2da059bSthorpej 
130c2da059bSthorpej percpu_t *udp6stat_percpu;
13174d3c214Sitojun 
1329a6de984Srmind /* UDP on IP6 parameters */
1339a6de984Srmind static int udp6_sendspace = 9216;	/* really max datagram size */
1349a6de984Srmind static int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6));
1359a6de984Srmind 					/* 40 1K datagrams */
1369a6de984Srmind 
1370e390eeeSozaki-r static void udp6_notify(struct inpcb *, int);
13811281f01Spooka static void sysctl_net_inet6_udp6_setup(struct sysctllog **);
139890dda53Sknakahara #ifdef IPSEC
140b9e11ce7Smaxv static int udp6_espinudp(struct mbuf **, int);
141890dda53Sknakahara #endif
14274d3c214Sitojun 
1439a6de984Srmind #ifdef UDP_CSUM_COUNTERS
1449a6de984Srmind #include <sys/device.h>
1459a6de984Srmind struct evcnt udp6_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
1469a6de984Srmind     NULL, "udp6", "hwcsum bad");
1479a6de984Srmind struct evcnt udp6_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
1489a6de984Srmind     NULL, "udp6", "hwcsum ok");
1499a6de984Srmind struct evcnt udp6_hwcsum_data = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
1509a6de984Srmind     NULL, "udp6", "hwcsum data");
1519a6de984Srmind struct evcnt udp6_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
1529a6de984Srmind     NULL, "udp6", "swcsum");
1539a6de984Srmind 
1549a6de984Srmind EVCNT_ATTACH_STATIC(udp6_hwcsum_bad);
1559a6de984Srmind EVCNT_ATTACH_STATIC(udp6_hwcsum_ok);
1569a6de984Srmind EVCNT_ATTACH_STATIC(udp6_hwcsum_data);
1579a6de984Srmind EVCNT_ATTACH_STATIC(udp6_swcsum);
1589a6de984Srmind 
1599a6de984Srmind #define	UDP_CSUM_COUNTER_INCR(ev)	(ev)->ev_count++
1609a6de984Srmind #else
1619a6de984Srmind #define	UDP_CSUM_COUNTER_INCR(ev)	/* nothing */
1629a6de984Srmind #endif
1639a6de984Srmind 
16474d3c214Sitojun void
16558bb9f65Smatt udp6_init(void)
16674d3c214Sitojun {
16711281f01Spooka 	sysctl_net_inet6_udp6_setup(NULL);
168acb67644Spooka 	udp6stat_percpu = percpu_alloc(sizeof(uint64_t) * UDP6_NSTATS);
169acb67644Spooka 
170acb67644Spooka 	udp_init_common();
17174d3c214Sitojun }
17274d3c214Sitojun 
17374d3c214Sitojun /*
17474d3c214Sitojun  * Notify a udp user of an asynchronous error;
17581e8059dSitojun  * just wake up so that he can collect error status.
17674d3c214Sitojun  */
17774d3c214Sitojun static	void
1780e390eeeSozaki-r udp6_notify(struct inpcb *inp, int errno)
17974d3c214Sitojun {
1800e390eeeSozaki-r 	inp->inp_socket->so_error = errno;
1810e390eeeSozaki-r 	sorwakeup(inp->inp_socket);
1820e390eeeSozaki-r 	sowwakeup(inp->inp_socket);
18374d3c214Sitojun }
18474d3c214Sitojun 
18515e29e98Sad void *
1865493f188Sdyoung udp6_ctlinput(int cmd, const struct sockaddr *sa, void *d)
18774d3c214Sitojun {
18874d3c214Sitojun 	struct udphdr uh;
189e1f4f779Sitojun 	struct ip6_hdr *ip6;
1905493f188Sdyoung 	const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)sa;
191ea861f01Sitojun 	struct mbuf *m;
192ea861f01Sitojun 	int off;
193bc5a6e24Sitojun 	void *cmdarg;
194bc5a6e24Sitojun 	struct ip6ctlparam *ip6cp = NULL;
195bc5a6e24Sitojun 	const struct sockaddr_in6 *sa6_src = NULL;
1960e390eeeSozaki-r 	void (*notify)(struct inpcb *, int) = udp6_notify;
197bc5a6e24Sitojun 	struct udp_portonly {
198bc5a6e24Sitojun 		u_int16_t uh_sport;
199bc5a6e24Sitojun 		u_int16_t uh_dport;
200bc5a6e24Sitojun 	} *uhp;
20174d3c214Sitojun 
202a9b7fe46Sitojun 	if (sa->sa_family != AF_INET6 ||
203a9b7fe46Sitojun 	    sa->sa_len != sizeof(struct sockaddr_in6))
20415e29e98Sad 		return NULL;
205ea861f01Sitojun 
20603f0ac37Sitojun 	if ((unsigned)cmd >= PRC_NCMDS)
20715e29e98Sad 		return NULL;
20803f0ac37Sitojun 	if (PRC_IS_REDIRECT(cmd))
209b000e63fSozaki-r 		notify = in6pcb_rtchange, d = NULL;
21003f0ac37Sitojun 	else if (cmd == PRC_HOSTDEAD)
21103f0ac37Sitojun 		d = NULL;
212ae549981Sitojun 	else if (cmd == PRC_MSGSIZE) {
213ae549981Sitojun 		/* special code is present, see below */
214b000e63fSozaki-r 		notify = in6pcb_rtchange;
215ae549981Sitojun 	}
21603f0ac37Sitojun 	else if (inet6ctlerrmap[cmd] == 0)
21715e29e98Sad 		return NULL;
21870ada095Sitojun 
219ea861f01Sitojun 	/* if the parameter is from icmp6, decode it. */
220ea861f01Sitojun 	if (d != NULL) {
221bc5a6e24Sitojun 		ip6cp = (struct ip6ctlparam *)d;
222ea861f01Sitojun 		m = ip6cp->ip6c_m;
223ea861f01Sitojun 		ip6 = ip6cp->ip6c_ip6;
224ea861f01Sitojun 		off = ip6cp->ip6c_off;
225bc5a6e24Sitojun 		cmdarg = ip6cp->ip6c_cmdarg;
226bc5a6e24Sitojun 		sa6_src = ip6cp->ip6c_src;
227ea861f01Sitojun 	} else {
228ea861f01Sitojun 		m = NULL;
229ea861f01Sitojun 		ip6 = NULL;
230bc5a6e24Sitojun 		cmdarg = NULL;
231bc5a6e24Sitojun 		sa6_src = &sa6_any;
23259f2aab1Schristos 		off = 0;
233ea861f01Sitojun 	}
234ea861f01Sitojun 
23574d3c214Sitojun 	if (ip6) {
2366e3a9bc3Sitojun 		/* check if we can safely examine src and dst ports */
237a7596d19Sitojun 		if (m->m_pkthdr.len < off + sizeof(*uhp)) {
238a7596d19Sitojun 			if (cmd == PRC_MSGSIZE)
239a7596d19Sitojun 				icmp6_mtudisc_update((struct ip6ctlparam *)d, 0);
24015e29e98Sad 			return NULL;
241a7596d19Sitojun 		}
2426e3a9bc3Sitojun 
243c363a9cbScegger 		memset(&uh, 0, sizeof(uh));
24453524e44Schristos 		m_copydata(m, off, sizeof(*uhp), (void *)&uh);
245edd876a3Sitojun 
246edd876a3Sitojun 		if (cmd == PRC_MSGSIZE) {
2475eae50d9Sitojun 			int valid = 0;
248bc5a6e24Sitojun 
249edd876a3Sitojun 			/*
250edd876a3Sitojun 			 * Check to see if we have a valid UDP socket
251edd876a3Sitojun 			 * corresponding to the address in the ICMPv6 message
252edd876a3Sitojun 			 * payload.
253edd876a3Sitojun 			 */
254b000e63fSozaki-r 			if (in6pcb_lookup(&udbtable, &sa6->sin6_addr,
2552ab31527Schristos 			    uh.uh_dport, (const struct in6_addr *)&sa6_src->sin6_addr,
256c2e43be1Sdyoung 			    uh.uh_sport, 0, 0))
2575eae50d9Sitojun 				valid++;
258edd876a3Sitojun #if 0
259edd876a3Sitojun 			/*
260edd876a3Sitojun 			 * As the use of sendto(2) is fairly popular,
261edd876a3Sitojun 			 * we may want to allow non-connected pcb too.
262edd876a3Sitojun 			 * But it could be too weak against attacks...
263edd876a3Sitojun 			 * We should at least check if the local address (= s)
264edd876a3Sitojun 			 * is really ours.
265edd876a3Sitojun 			 */
266b000e63fSozaki-r 			else if (in6pcb_lookup_bound(&udbtable, &sa6->sin6_addr,
267bc5a6e24Sitojun 			    uh.uh_dport, 0))
2685eae50d9Sitojun 				valid++;
269edd876a3Sitojun #endif
270edd876a3Sitojun 
271edd876a3Sitojun 			/*
272bc5a6e24Sitojun 			 * Depending on the value of "valid" and routing table
273bc5a6e24Sitojun 			 * size (mtudisc_{hi,lo}wat), we will:
27491498ffeSitojun 			 * - recalculate the new MTU and create the
275bc5a6e24Sitojun 			 *   corresponding routing entry, or
276bc5a6e24Sitojun 			 * - ignore the MTU change notification.
277edd876a3Sitojun 			 */
2785eae50d9Sitojun 			icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
279edd876a3Sitojun 
280bc5a6e24Sitojun 			/*
281de8db475Srpaulo 			 * regardless of if we called
282de8db475Srpaulo 			 * icmp6_mtudisc_update(), we need to call
283b000e63fSozaki-r 			 * in6pcb_notify(), to notify path MTU change
284de8db475Srpaulo 			 * to the userland (RFC3542), because some
285de8db475Srpaulo 			 * unconnected sockets may share the same
286bc5a6e24Sitojun 			 * destination and want to know the path MTU.
287bc5a6e24Sitojun 			 */
288edd876a3Sitojun 		}
289edd876a3Sitojun 
290b000e63fSozaki-r 		(void)in6pcb_notify(&udbtable, sa, uh.uh_dport,
2918759207cSozaki-r 		    sin6tocsa(sa6_src), uh.uh_sport, cmd, cmdarg,
292bc5a6e24Sitojun 		    notify);
29374d3c214Sitojun 	} else {
294b000e63fSozaki-r 		(void)in6pcb_notify(&udbtable, sa, 0,
2958759207cSozaki-r 		    sin6tocsa(sa6_src), 0, cmd, cmdarg, notify);
29674d3c214Sitojun 	}
29715e29e98Sad 	return NULL;
29874d3c214Sitojun }
29974d3c214Sitojun 
3005ec72efbSchristos int
3015ec72efbSchristos udp6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
3025ec72efbSchristos {
3035ec72efbSchristos 	int s;
3045ec72efbSchristos 	int error = 0;
3050e390eeeSozaki-r 	struct inpcb *inp;
3065ec72efbSchristos 	int family;
307890dda53Sknakahara 	int optval;
3085ec72efbSchristos 
3095ec72efbSchristos 	family = so->so_proto->pr_domain->dom_family;
3105ec72efbSchristos 
3115ec72efbSchristos 	s = splsoftnet();
3125ec72efbSchristos 	switch (family) {
3135ec72efbSchristos #ifdef INET
3145ec72efbSchristos 	case PF_INET:
3155ec72efbSchristos 		if (sopt->sopt_level != IPPROTO_UDP) {
3165ec72efbSchristos 			error = ip_ctloutput(op, so, sopt);
3175ec72efbSchristos 			goto end;
3185ec72efbSchristos 		}
3195ec72efbSchristos 		break;
3205ec72efbSchristos #endif
3215ec72efbSchristos #ifdef INET6
3225ec72efbSchristos 	case PF_INET6:
3235ec72efbSchristos 		if (sopt->sopt_level != IPPROTO_UDP) {
3245ec72efbSchristos 			error = ip6_ctloutput(op, so, sopt);
3255ec72efbSchristos 			goto end;
3265ec72efbSchristos 		}
3275ec72efbSchristos 		break;
3285ec72efbSchristos #endif
3295ec72efbSchristos 	default:
3305ec72efbSchristos 		error = EAFNOSUPPORT;
3315ec72efbSchristos 		goto end;
3325ec72efbSchristos 	}
333890dda53Sknakahara 
334890dda53Sknakahara 	switch (op) {
335890dda53Sknakahara 	case PRCO_SETOPT:
3360e390eeeSozaki-r 		inp = sotoinpcb(so);
337890dda53Sknakahara 
338890dda53Sknakahara 		switch (sopt->sopt_name) {
339890dda53Sknakahara 		case UDP_ENCAP:
340890dda53Sknakahara 			error = sockopt_getint(sopt, &optval);
341890dda53Sknakahara 			if (error)
342890dda53Sknakahara 				break;
343890dda53Sknakahara 
344890dda53Sknakahara 			switch(optval) {
345890dda53Sknakahara 			case 0:
3460e390eeeSozaki-r 				inp->inp_flags &= ~IN6P_ESPINUDP;
347890dda53Sknakahara 				break;
348890dda53Sknakahara 
349890dda53Sknakahara 			case UDP_ENCAP_ESPINUDP:
3500e390eeeSozaki-r 				inp->inp_flags |= IN6P_ESPINUDP;
351890dda53Sknakahara 				break;
352890dda53Sknakahara 
353890dda53Sknakahara 			default:
3545ec72efbSchristos 				error = EINVAL;
355890dda53Sknakahara 				break;
356890dda53Sknakahara 			}
357890dda53Sknakahara 			break;
358890dda53Sknakahara 
359890dda53Sknakahara 		default:
360890dda53Sknakahara 			error = ENOPROTOOPT;
361890dda53Sknakahara 			break;
362890dda53Sknakahara 		}
363890dda53Sknakahara 		break;
364890dda53Sknakahara 
365890dda53Sknakahara 	default:
366890dda53Sknakahara 		error = EINVAL;
367890dda53Sknakahara 		break;
368890dda53Sknakahara 	}
3695ec72efbSchristos 
3705ec72efbSchristos end:
3715ec72efbSchristos 	splx(s);
3725ec72efbSchristos 	return error;
3735ec72efbSchristos }
3745ec72efbSchristos 
3759a6de984Srmind static void
3769a6de984Srmind udp6_sendup(struct mbuf *m, int off /* offset of data portion */,
3779a6de984Srmind     struct sockaddr *src, struct socket *so)
3789a6de984Srmind {
3799a6de984Srmind 	struct mbuf *opts = NULL;
3809a6de984Srmind 	struct mbuf *n;
3810e390eeeSozaki-r 	struct inpcb *inp;
3825ec72efbSchristos 
383c4cc9034Sozaki-r 	KASSERT(so != NULL);
384c4cc9034Sozaki-r 	KASSERT(so->so_proto->pr_domain->dom_family == AF_INET6);
3850e390eeeSozaki-r 	inp = sotoinpcb(so);
3860e390eeeSozaki-r 	KASSERT(inp != NULL);
3879a6de984Srmind 
3889a6de984Srmind #if defined(IPSEC)
3890e390eeeSozaki-r 	if (ipsec_used && ipsec_in_reject(m, inp)) {
3909a6de984Srmind 		if ((n = m_copypacket(m, M_DONTWAIT)) != NULL)
3919a6de984Srmind 			icmp6_error(n, ICMP6_DST_UNREACH,
3929a6de984Srmind 			    ICMP6_DST_UNREACH_ADMIN, 0);
3939a6de984Srmind 		return;
3949a6de984Srmind 	}
395d6071245Smaxv #endif
3969a6de984Srmind 
3979a6de984Srmind 	if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
3980e390eeeSozaki-r 		if (inp->inp_flags & IN6P_CONTROLOPTS ||
3990e390eeeSozaki-r 		    SOOPT_TIMESTAMP(inp->inp_socket->so_options)) {
4009a6de984Srmind 			struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *);
4010e390eeeSozaki-r 			ip6_savecontrol(inp, &opts, ip6, n);
4029a6de984Srmind 		}
4039a6de984Srmind 
4049a6de984Srmind 		m_adj(n, off);
4059a6de984Srmind 		if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) {
4069a6de984Srmind 			m_freem(n);
4079a6de984Srmind 			m_freem(opts);
4089a6de984Srmind 			UDP6_STATINC(UDP6_STAT_FULLSOCK);
409320ba6e2Sroy 			soroverflow(so);
4109a6de984Srmind 		} else
4119a6de984Srmind 			sorwakeup(so);
4129a6de984Srmind 	}
4139a6de984Srmind }
4149a6de984Srmind 
4159a6de984Srmind int
4169a6de984Srmind udp6_realinput(int af, struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
417890dda53Sknakahara     struct mbuf **mp, int off)
4189a6de984Srmind {
4199a6de984Srmind 	u_int16_t sport, dport;
4209a6de984Srmind 	int rcvcnt;
4219a6de984Srmind 	struct in6_addr src6, *dst6;
4229a6de984Srmind 	const struct in_addr *dst4;
4230e390eeeSozaki-r 	struct inpcb *inp;
424890dda53Sknakahara 	struct mbuf *m = *mp;
4259a6de984Srmind 
4269a6de984Srmind 	rcvcnt = 0;
4279a6de984Srmind 	off += sizeof(struct udphdr);	/* now, offset of payload */
4289a6de984Srmind 
4299a6de984Srmind 	if (af != AF_INET && af != AF_INET6)
4309a6de984Srmind 		goto bad;
4319a6de984Srmind 	if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6)
4329a6de984Srmind 		goto bad;
4339a6de984Srmind 
4349a6de984Srmind 	src6 = src->sin6_addr;
4359a6de984Srmind 	if (sa6_recoverscope(src) != 0) {
4369a6de984Srmind 		/* XXX: should be impossible. */
4379a6de984Srmind 		goto bad;
4389a6de984Srmind 	}
4399a6de984Srmind 	sport = src->sin6_port;
4409a6de984Srmind 
4419a6de984Srmind 	dport = dst->sin6_port;
4429a6de984Srmind 	dst4 = (struct in_addr *)&dst->sin6_addr.s6_addr[12];
4439a6de984Srmind 	dst6 = &dst->sin6_addr;
4449a6de984Srmind 
4459a6de984Srmind 	if (IN6_IS_ADDR_MULTICAST(dst6) ||
4469a6de984Srmind 	    (af == AF_INET && IN_MULTICAST(dst4->s_addr))) {
4479a6de984Srmind 		/*
4489a6de984Srmind 		 * Deliver a multicast or broadcast datagram to *all* sockets
4499a6de984Srmind 		 * for which the local and remote addresses and ports match
4509a6de984Srmind 		 * those of the incoming datagram.  This allows more than
4519a6de984Srmind 		 * one process to receive multi/broadcasts on the same port.
4529a6de984Srmind 		 * (This really ought to be done for unicast datagrams as
4539a6de984Srmind 		 * well, but that would cause problems with existing
4549a6de984Srmind 		 * applications that open both address-specific sockets and
4559a6de984Srmind 		 * a wildcard socket listening to the same port -- they would
4569a6de984Srmind 		 * end up receiving duplicates of every unicast datagram.
4579a6de984Srmind 		 * Those applications open the multiple sockets to overcome an
4589a6de984Srmind 		 * inadequacy of the UDP socket interface, but for backwards
4599a6de984Srmind 		 * compatibility we avoid the problem here rather than
4609a6de984Srmind 		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
4619a6de984Srmind 		 */
4629a6de984Srmind 
4639a6de984Srmind 		/*
4649a6de984Srmind 		 * KAME note: traditionally we dropped udpiphdr from mbuf here.
4659a6de984Srmind 		 * we need udpiphdr for IPsec processing so we do that later.
4669a6de984Srmind 		 */
4679a6de984Srmind 		/*
4689a6de984Srmind 		 * Locate pcb(s) for datagram.
4699a6de984Srmind 		 */
4700e390eeeSozaki-r 		TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) {
4710e390eeeSozaki-r 			if (inp->inp_af != AF_INET6)
4729a6de984Srmind 				continue;
4739a6de984Srmind 
4740e390eeeSozaki-r 			if (inp->inp_lport != dport)
4759a6de984Srmind 				continue;
476a071c829Sozaki-r 			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_laddr(inp))) {
477a071c829Sozaki-r 				if (!IN6_ARE_ADDR_EQUAL(&in6p_laddr(inp),
4789a6de984Srmind 				    dst6))
4799a6de984Srmind 					continue;
4809a6de984Srmind 			} else {
4819a6de984Srmind 				if (IN6_IS_ADDR_V4MAPPED(dst6) &&
4820e390eeeSozaki-r 				    (inp->inp_flags & IN6P_IPV6_V6ONLY))
4839a6de984Srmind 					continue;
4849a6de984Srmind 			}
485a071c829Sozaki-r 			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp))) {
486a071c829Sozaki-r 				if (!IN6_ARE_ADDR_EQUAL(&in6p_faddr(inp),
4870e390eeeSozaki-r 				    &src6) || inp->inp_fport != sport)
4889a6de984Srmind 					continue;
4899a6de984Srmind 			} else {
4909a6de984Srmind 				if (IN6_IS_ADDR_V4MAPPED(&src6) &&
4910e390eeeSozaki-r 				    (inp->inp_flags & IN6P_IPV6_V6ONLY))
4929a6de984Srmind 					continue;
4939a6de984Srmind 			}
4949a6de984Srmind 
4950e390eeeSozaki-r 			udp6_sendup(m, off, sin6tosa(src), inp->inp_socket);
4969a6de984Srmind 			rcvcnt++;
4979a6de984Srmind 
4989a6de984Srmind 			/*
4999a6de984Srmind 			 * Don't look for additional matches if this one does
5009a6de984Srmind 			 * not have either the SO_REUSEPORT or SO_REUSEADDR
5019a6de984Srmind 			 * socket options set.  This heuristic avoids searching
5029a6de984Srmind 			 * through all pcbs in the common case of a non-shared
5039a6de984Srmind 			 * port.  It assumes that an application will never
5049a6de984Srmind 			 * clear these options after setting them.
5059a6de984Srmind 			 */
5060e390eeeSozaki-r 			if ((inp->inp_socket->so_options &
5079a6de984Srmind 			    (SO_REUSEPORT|SO_REUSEADDR)) == 0)
5089a6de984Srmind 				break;
5099a6de984Srmind 		}
5109a6de984Srmind 	} else {
5119a6de984Srmind 		/*
5129a6de984Srmind 		 * Locate pcb for datagram.
5139a6de984Srmind 		 */
514b000e63fSozaki-r 		inp = in6pcb_lookup(&udbtable, &src6, sport, dst6,
5159a6de984Srmind 					     dport, 0, 0);
5160e390eeeSozaki-r 		if (inp == NULL) {
5179a6de984Srmind 			UDP_STATINC(UDP_STAT_PCBHASHMISS);
518b000e63fSozaki-r 			inp = in6pcb_lookup_bound(&udbtable, dst6, dport, 0);
5190e390eeeSozaki-r 			if (inp == NULL)
5209a6de984Srmind 				return rcvcnt;
5219a6de984Srmind 		}
5229a6de984Srmind 
523890dda53Sknakahara #ifdef IPSEC
524890dda53Sknakahara 		/* Handle ESP over UDP */
5250e390eeeSozaki-r 		if (inp->inp_flags & IN6P_ESPINUDP) {
526b9e11ce7Smaxv 			switch (udp6_espinudp(mp, off)) {
527890dda53Sknakahara 			case -1: /* Error, m was freed */
528*5d781b6fSriastradh 				KASSERT(*mp == NULL);
529890dda53Sknakahara 				rcvcnt = -1;
530890dda53Sknakahara 				goto bad;
531890dda53Sknakahara 
532890dda53Sknakahara 			case 1: /* ESP over UDP */
533*5d781b6fSriastradh 				KASSERT(*mp == NULL);
534890dda53Sknakahara 				rcvcnt++;
535890dda53Sknakahara 				goto bad;
536890dda53Sknakahara 
537890dda53Sknakahara 			case 0: /* plain UDP */
538890dda53Sknakahara 			default: /* Unexpected */
539890dda53Sknakahara 				/*
540890dda53Sknakahara 				 * Normal UDP processing will take place,
541890dda53Sknakahara 				 * m may have changed.
542890dda53Sknakahara 				 */
543890dda53Sknakahara 				m = *mp;
544890dda53Sknakahara 				break;
545890dda53Sknakahara 			}
546890dda53Sknakahara 		}
547890dda53Sknakahara #endif
548890dda53Sknakahara 
5490e390eeeSozaki-r 		if (inp->inp_overudp_cb != NULL) {
550a14187ecSriastradh 			int ret;
5510e390eeeSozaki-r 			ret = inp->inp_overudp_cb(mp, off, inp->inp_socket,
5520e390eeeSozaki-r 			    sin6tosa(src), inp->inp_overudp_arg);
553a14187ecSriastradh 			switch (ret) {
554a14187ecSriastradh 			case -1: /* Error, m was freed */
555*5d781b6fSriastradh 				KASSERT(*mp == NULL);
556a14187ecSriastradh 				rcvcnt = -1;
557a14187ecSriastradh 				goto bad;
558a14187ecSriastradh 
559a14187ecSriastradh 			case 1: /* Foo over UDP */
560a14187ecSriastradh 				KASSERT(*mp == NULL);
561a14187ecSriastradh 				rcvcnt++;
562a14187ecSriastradh 				goto bad;
563a14187ecSriastradh 
564a14187ecSriastradh 			case 0: /* plain UDP */
565a14187ecSriastradh 			default: /* Unexpected */
566a14187ecSriastradh 				/*
567a14187ecSriastradh 				 * Normal UDP processing will take place,
568a14187ecSriastradh 				 * m may have changed.
569a14187ecSriastradh 				 */
570*5d781b6fSriastradh 				m = *mp;
571a14187ecSriastradh 				break;
572a14187ecSriastradh 			}
573a14187ecSriastradh 		}
574a14187ecSriastradh 
5750e390eeeSozaki-r 		udp6_sendup(m, off, sin6tosa(src), inp->inp_socket);
5769a6de984Srmind 		rcvcnt++;
5779a6de984Srmind 	}
5789a6de984Srmind 
5799a6de984Srmind bad:
5809a6de984Srmind 	return rcvcnt;
5819a6de984Srmind }
5829a6de984Srmind 
5839a6de984Srmind int
5849a6de984Srmind udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len)
5859a6de984Srmind {
5869a6de984Srmind 
5879a6de984Srmind 	/*
5889a6de984Srmind 	 * XXX it's better to record and check if this mbuf is
5899a6de984Srmind 	 * already checked.
5909a6de984Srmind 	 */
5919a6de984Srmind 
5929a6de984Srmind 	if (__predict_false((m->m_flags & M_LOOP) && !udp_do_loopback_cksum)) {
5939a6de984Srmind 		goto good;
5949a6de984Srmind 	}
5959a6de984Srmind 	if (uh->uh_sum == 0) {
5969a6de984Srmind 		UDP6_STATINC(UDP6_STAT_NOSUM);
5979a6de984Srmind 		goto bad;
5989a6de984Srmind 	}
5999a6de984Srmind 
6009a6de984Srmind 	switch (m->m_pkthdr.csum_flags &
601fe6d4275Sozaki-r 	    ((m_get_rcvif_NOMPSAFE(m)->if_csum_flags_rx & M_CSUM_UDPv6) |
6029a6de984Srmind 	    M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) {
6039a6de984Srmind 	case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD:
6049a6de984Srmind 		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad);
6059a6de984Srmind 		UDP6_STATINC(UDP6_STAT_BADSUM);
6069a6de984Srmind 		goto bad;
6079a6de984Srmind 
6089a6de984Srmind #if 0 /* notyet */
6099a6de984Srmind 	case M_CSUM_UDPv6|M_CSUM_DATA:
6109a6de984Srmind #endif
6119a6de984Srmind 
6129a6de984Srmind 	case M_CSUM_UDPv6:
6139a6de984Srmind 		/* Checksum was okay. */
6149a6de984Srmind 		UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_ok);
6159a6de984Srmind 		break;
6169a6de984Srmind 
6179a6de984Srmind 	default:
6189a6de984Srmind 		/*
6199a6de984Srmind 		 * Need to compute it ourselves.  Maybe skip checksum
6209a6de984Srmind 		 * on loopback interfaces.
6219a6de984Srmind 		 */
6229a6de984Srmind 		UDP_CSUM_COUNTER_INCR(&udp6_swcsum);
6239a6de984Srmind 		if (in6_cksum(m, IPPROTO_UDP, off, len) != 0) {
6249a6de984Srmind 			UDP6_STATINC(UDP6_STAT_BADSUM);
6259a6de984Srmind 			goto bad;
6269a6de984Srmind 		}
6279a6de984Srmind 	}
6289a6de984Srmind 
6299a6de984Srmind good:
6309a6de984Srmind 	return 0;
6319a6de984Srmind bad:
6329a6de984Srmind 	return -1;
6339a6de984Srmind }
6349a6de984Srmind 
6359a6de984Srmind int
6369a6de984Srmind udp6_input(struct mbuf **mp, int *offp, int proto)
6379a6de984Srmind {
6389a6de984Srmind 	struct mbuf *m = *mp;
6399a6de984Srmind 	int off = *offp;
6409a6de984Srmind 	struct sockaddr_in6 src, dst;
6419a6de984Srmind 	struct ip6_hdr *ip6;
6429a6de984Srmind 	struct udphdr *uh;
6439a6de984Srmind 	u_int32_t plen, ulen;
6449a6de984Srmind 
6459a6de984Srmind 	ip6 = mtod(m, struct ip6_hdr *);
6469a6de984Srmind 
6479a6de984Srmind #if defined(NFAITH) && 0 < NFAITH
6489a6de984Srmind 	if (faithprefix(&ip6->ip6_dst)) {
6499a6de984Srmind 		/* send icmp6 host unreach? */
6509a6de984Srmind 		m_freem(m);
6519a6de984Srmind 		return IPPROTO_DONE;
6529a6de984Srmind 	}
6539a6de984Srmind #endif
6549a6de984Srmind 
6559a6de984Srmind 	UDP6_STATINC(UDP6_STAT_IPACKETS);
6569a6de984Srmind 
657d6071245Smaxv 	/* Check for jumbogram is done in ip6_input. We can trust pkthdr.len. */
6589a6de984Srmind 	plen = m->m_pkthdr.len - off;
6599a6de984Srmind 	IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
6609a6de984Srmind 	if (uh == NULL) {
6619a6de984Srmind 		IP6_STATINC(IP6_STAT_TOOSHORT);
6629a6de984Srmind 		return IPPROTO_DONE;
6639a6de984Srmind 	}
664d6071245Smaxv 
665845a5992Smlelstv 	/*
666845a5992Smlelstv 	 * Enforce alignment requirements that are violated in
667845a5992Smlelstv 	 * some cases, see kern/50766 for details.
668845a5992Smlelstv 	 */
6692143da87Schristos 	if (ACCESSIBLE_POINTER(uh, struct udphdr) == 0) {
670845a5992Smlelstv 		m = m_copyup(m, off + sizeof(struct udphdr), 0);
671845a5992Smlelstv 		if (m == NULL) {
672845a5992Smlelstv 			IP6_STATINC(IP6_STAT_TOOSHORT);
673845a5992Smlelstv 			return IPPROTO_DONE;
674845a5992Smlelstv 		}
675845a5992Smlelstv 		ip6 = mtod(m, struct ip6_hdr *);
676845a5992Smlelstv 		uh = (struct udphdr *)(mtod(m, char *) + off);
677845a5992Smlelstv 	}
6782143da87Schristos 	KASSERT(ACCESSIBLE_POINTER(uh, struct udphdr));
6799a6de984Srmind 	ulen = ntohs((u_short)uh->uh_ulen);
680d6071245Smaxv 
6819a6de984Srmind 	/*
6829a6de984Srmind 	 * RFC2675 section 4: jumbograms will have 0 in the UDP header field,
6839a6de984Srmind 	 * iff payload length > 0xffff.
6849a6de984Srmind 	 */
6859a6de984Srmind 	if (ulen == 0 && plen > 0xffff)
6869a6de984Srmind 		ulen = plen;
6879a6de984Srmind 
6889a6de984Srmind 	if (plen != ulen) {
6899a6de984Srmind 		UDP6_STATINC(UDP6_STAT_BADLEN);
6909a6de984Srmind 		goto bad;
6919a6de984Srmind 	}
6929a6de984Srmind 
6939a6de984Srmind 	/* destination port of 0 is illegal, based on RFC768. */
6949a6de984Srmind 	if (uh->uh_dport == 0)
6959a6de984Srmind 		goto bad;
6969a6de984Srmind 
6979a6de984Srmind 	/*
6989a6de984Srmind 	 * Checksum extended UDP header and data.  Maybe skip checksum
6999a6de984Srmind 	 * on loopback interfaces.
7009a6de984Srmind 	 */
7019a6de984Srmind 	if (udp6_input_checksum(m, uh, off, ulen))
7029a6de984Srmind 		goto bad;
7039a6de984Srmind 
7049a6de984Srmind 	/*
7059a6de984Srmind 	 * Construct source and dst sockaddrs.
7069a6de984Srmind 	 */
7079a6de984Srmind 	memset(&src, 0, sizeof(src));
7089a6de984Srmind 	src.sin6_family = AF_INET6;
7099a6de984Srmind 	src.sin6_len = sizeof(struct sockaddr_in6);
7109a6de984Srmind 	src.sin6_addr = ip6->ip6_src;
7119a6de984Srmind 	src.sin6_port = uh->uh_sport;
7129a6de984Srmind 	memset(&dst, 0, sizeof(dst));
7139a6de984Srmind 	dst.sin6_family = AF_INET6;
7149a6de984Srmind 	dst.sin6_len = sizeof(struct sockaddr_in6);
7159a6de984Srmind 	dst.sin6_addr = ip6->ip6_dst;
7169a6de984Srmind 	dst.sin6_port = uh->uh_dport;
7179a6de984Srmind 
718890dda53Sknakahara 	if (udp6_realinput(AF_INET6, &src, &dst, &m, off) == 0) {
7199a6de984Srmind 		if (m->m_flags & M_MCAST) {
7209a6de984Srmind 			UDP6_STATINC(UDP6_STAT_NOPORTMCAST);
7219a6de984Srmind 			goto bad;
7229a6de984Srmind 		}
7239a6de984Srmind 		UDP6_STATINC(UDP6_STAT_NOPORT);
7249a6de984Srmind 		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
7259a6de984Srmind 		m = NULL;
7269a6de984Srmind 	}
7279a6de984Srmind 
7289a6de984Srmind bad:
7299a6de984Srmind 	m_freem(m);
7309a6de984Srmind 	return IPPROTO_DONE;
7319a6de984Srmind }
73274d3c214Sitojun 
73363ecc40cSmaxv int
7340e390eeeSozaki-r udp6_output(struct inpcb * const inp, struct mbuf *m,
73563ecc40cSmaxv     struct sockaddr_in6 * const addr6, struct mbuf * const control,
73663ecc40cSmaxv     struct lwp * const l)
73763ecc40cSmaxv {
73863ecc40cSmaxv 	u_int32_t ulen = m->m_pkthdr.len;
73963ecc40cSmaxv 	u_int32_t plen = sizeof(struct udphdr) + ulen;
74063ecc40cSmaxv 	struct ip6_hdr *ip6;
74163ecc40cSmaxv 	struct udphdr *udp6;
74263ecc40cSmaxv 	struct in6_addr _laddr, *laddr, *faddr;
74363ecc40cSmaxv 	struct in6_addr laddr_mapped; /* XXX ugly */
74463ecc40cSmaxv 	struct sockaddr_in6 *sin6 = NULL;
74563ecc40cSmaxv 	struct ifnet *oifp = NULL;
74663ecc40cSmaxv 	int scope_ambiguous = 0;
74763ecc40cSmaxv 	u_int16_t fport;
74863ecc40cSmaxv 	int error = 0;
74963ecc40cSmaxv 	struct ip6_pktopts *optp = NULL;
75063ecc40cSmaxv 	struct ip6_pktopts opt;
75163ecc40cSmaxv 	int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
75263ecc40cSmaxv #ifdef INET
75363ecc40cSmaxv 	struct ip *ip;
75463ecc40cSmaxv 	struct udpiphdr *ui;
75563ecc40cSmaxv 	int flags = 0;
75663ecc40cSmaxv #endif
75763ecc40cSmaxv 	struct sockaddr_in6 tmp;
75863ecc40cSmaxv 
75963ecc40cSmaxv 	if (addr6) {
76063ecc40cSmaxv 		sin6 = addr6;
7611266a13dSozaki-r 		if (sin6->sin6_len != sizeof(*sin6)) {
7621266a13dSozaki-r 			error = EINVAL;
7631266a13dSozaki-r 			goto release;
7641266a13dSozaki-r 		}
76563ecc40cSmaxv 		if (sin6->sin6_family != AF_INET6) {
76663ecc40cSmaxv 			error = EAFNOSUPPORT;
76763ecc40cSmaxv 			goto release;
76863ecc40cSmaxv 		}
76963ecc40cSmaxv 
77063ecc40cSmaxv 		/* protect *sin6 from overwrites */
77163ecc40cSmaxv 		tmp = *sin6;
77263ecc40cSmaxv 		sin6 = &tmp;
77363ecc40cSmaxv 
77463ecc40cSmaxv 		/*
77563ecc40cSmaxv 		 * Application should provide a proper zone ID or the use of
77663ecc40cSmaxv 		 * default zone IDs should be enabled.  Unfortunately, some
77763ecc40cSmaxv 		 * applications do not behave as it should, so we need a
77863ecc40cSmaxv 		 * workaround.  Even if an appropriate ID is not determined,
77963ecc40cSmaxv 		 * we'll see if we can determine the outgoing interface.  If we
78063ecc40cSmaxv 		 * can, determine the zone ID based on the interface below.
78163ecc40cSmaxv 		 */
78263ecc40cSmaxv 		if (sin6->sin6_scope_id == 0 && !ip6_use_defzone)
78363ecc40cSmaxv 			scope_ambiguous = 1;
78463ecc40cSmaxv 		if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0)
78563ecc40cSmaxv 			goto release;
78663ecc40cSmaxv 	}
78763ecc40cSmaxv 
78863ecc40cSmaxv 	if (control) {
78951ef7ebaSmaxv 		if (__predict_false(l == NULL)) {
79051ef7ebaSmaxv 			panic("%s: control but no lwp", __func__);
79151ef7ebaSmaxv 		}
79263ecc40cSmaxv 		if ((error = ip6_setpktopts(control, &opt,
793a071c829Sozaki-r 		    in6p_outputopts(inp), l->l_cred, IPPROTO_UDP)) != 0)
79463ecc40cSmaxv 			goto release;
79563ecc40cSmaxv 		optp = &opt;
79663ecc40cSmaxv 	} else
797a071c829Sozaki-r 		optp = in6p_outputopts(inp);
79863ecc40cSmaxv 
79963ecc40cSmaxv 
80063ecc40cSmaxv 	if (sin6) {
80163ecc40cSmaxv 		/*
80263ecc40cSmaxv 		 * Slightly different than v4 version in that we call
803b000e63fSozaki-r 		 * in6_selectsrc and in6pcb_set_port to fill in the local
8042ba9f052Sozaki-r 		 * address and port rather than inpcb_connect. inpcb_connect
8050e390eeeSozaki-r 		 * sets inp_faddr which causes EISCONN below to be hit on
80663ecc40cSmaxv 		 * subsequent sendto.
80763ecc40cSmaxv 		 */
80863ecc40cSmaxv 		if (sin6->sin6_port == 0) {
80963ecc40cSmaxv 			error = EADDRNOTAVAIL;
81063ecc40cSmaxv 			goto release;
81163ecc40cSmaxv 		}
81263ecc40cSmaxv 
813a071c829Sozaki-r 		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp))) {
81463ecc40cSmaxv 			/* how about ::ffff:0.0.0.0 case? */
81563ecc40cSmaxv 			error = EISCONN;
81663ecc40cSmaxv 			goto release;
81763ecc40cSmaxv 		}
81863ecc40cSmaxv 
81963ecc40cSmaxv 		faddr = &sin6->sin6_addr;
82063ecc40cSmaxv 		fport = sin6->sin6_port; /* allow 0 port */
82163ecc40cSmaxv 
82263ecc40cSmaxv 		if (IN6_IS_ADDR_V4MAPPED(faddr)) {
8230e390eeeSozaki-r 			if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) {
82463ecc40cSmaxv 				/*
82563ecc40cSmaxv 				 * I believe we should explicitly discard the
82663ecc40cSmaxv 				 * packet when mapped addresses are disabled,
82763ecc40cSmaxv 				 * rather than send the packet as an IPv6 one.
82863ecc40cSmaxv 				 * If we chose the latter approach, the packet
82963ecc40cSmaxv 				 * might be sent out on the wire based on the
83063ecc40cSmaxv 				 * default route, the situation which we'd
83163ecc40cSmaxv 				 * probably want to avoid.
83263ecc40cSmaxv 				 * (20010421 jinmei@kame.net)
83363ecc40cSmaxv 				 */
83463ecc40cSmaxv 				error = EINVAL;
83563ecc40cSmaxv 				goto release;
83663ecc40cSmaxv 			}
837a071c829Sozaki-r 			if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_laddr(inp)) &&
838a071c829Sozaki-r 			    !IN6_IS_ADDR_V4MAPPED(&in6p_laddr(inp))) {
83963ecc40cSmaxv 				/*
84063ecc40cSmaxv 				 * when remote addr is an IPv4-mapped address,
84163ecc40cSmaxv 				 * local addr should not be an IPv6 address,
84263ecc40cSmaxv 				 * since you cannot determine how to map IPv6
84363ecc40cSmaxv 				 * source address to IPv4.
84463ecc40cSmaxv 				 */
84563ecc40cSmaxv 				error = EINVAL;
84663ecc40cSmaxv 				goto release;
84763ecc40cSmaxv 			}
84863ecc40cSmaxv 
84963ecc40cSmaxv 			af = AF_INET;
85063ecc40cSmaxv 		}
85163ecc40cSmaxv 
85263ecc40cSmaxv 		if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
85363ecc40cSmaxv 			struct psref psref;
85463ecc40cSmaxv 			int bound = curlwp_bind();
85563ecc40cSmaxv 
85663ecc40cSmaxv 			error = in6_selectsrc(sin6, optp,
857a071c829Sozaki-r 			    in6p_moptions(inp),
8580e390eeeSozaki-r 			    &inp->inp_route,
859a071c829Sozaki-r 			    &in6p_laddr(inp), &oifp, &psref, &_laddr);
8605fdff786Smlelstv 			if (error)
8615fdff786Smlelstv 				laddr = NULL;
8625fdff786Smlelstv 			else
8635fdff786Smlelstv 				laddr = &_laddr;
86463ecc40cSmaxv 			if (oifp && scope_ambiguous &&
86563ecc40cSmaxv 			    (error = in6_setscope(&sin6->sin6_addr,
86663ecc40cSmaxv 			    oifp, NULL))) {
86763ecc40cSmaxv 				if_put(oifp, &psref);
86863ecc40cSmaxv 				curlwp_bindx(bound);
86963ecc40cSmaxv 				goto release;
87063ecc40cSmaxv 			}
87163ecc40cSmaxv 			if_put(oifp, &psref);
87263ecc40cSmaxv 			curlwp_bindx(bound);
87363ecc40cSmaxv 		} else {
87463ecc40cSmaxv 			/*
87563ecc40cSmaxv 			 * XXX: freebsd[34] does not have in_selectsrc, but
87663ecc40cSmaxv 			 * we can omit the whole part because freebsd4 calls
87763ecc40cSmaxv 			 * udp_output() directly in this case, and thus we'll
87863ecc40cSmaxv 			 * never see this path.
87963ecc40cSmaxv 			 */
880a071c829Sozaki-r 			if (IN6_IS_ADDR_UNSPECIFIED(&in6p_laddr(inp))) {
88163ecc40cSmaxv 				struct sockaddr_in sin_dst;
88263ecc40cSmaxv 				struct in_addr ina;
88363ecc40cSmaxv 				struct in_ifaddr *ia4;
88463ecc40cSmaxv 				struct psref _psref;
88563ecc40cSmaxv 				int bound;
88663ecc40cSmaxv 
88763ecc40cSmaxv 				memcpy(&ina, &faddr->s6_addr[12], sizeof(ina));
88863ecc40cSmaxv 				sockaddr_in_init(&sin_dst, &ina, 0);
88963ecc40cSmaxv 				bound = curlwp_bind();
8900e390eeeSozaki-r 				ia4 = in_selectsrc(&sin_dst, &inp->inp_route,
8910e390eeeSozaki-r 				    inp->inp_socket->so_options, NULL,
89263ecc40cSmaxv 				    &error, &_psref);
89363ecc40cSmaxv 				if (ia4 == NULL) {
89463ecc40cSmaxv 					curlwp_bindx(bound);
89563ecc40cSmaxv 					if (error == 0)
89663ecc40cSmaxv 						error = EADDRNOTAVAIL;
89763ecc40cSmaxv 					goto release;
89863ecc40cSmaxv 				}
89963ecc40cSmaxv 				memset(&laddr_mapped, 0, sizeof(laddr_mapped));
90063ecc40cSmaxv 				laddr_mapped.s6_addr16[5] = 0xffff; /* ugly */
90163ecc40cSmaxv 				memcpy(&laddr_mapped.s6_addr[12],
90263ecc40cSmaxv 				      &IA_SIN(ia4)->sin_addr,
90363ecc40cSmaxv 				      sizeof(IA_SIN(ia4)->sin_addr));
90463ecc40cSmaxv 				ia4_release(ia4, &_psref);
90563ecc40cSmaxv 				curlwp_bindx(bound);
90663ecc40cSmaxv 				laddr = &laddr_mapped;
90763ecc40cSmaxv 			} else
90863ecc40cSmaxv 			{
909a071c829Sozaki-r 				laddr = &in6p_laddr(inp);	/* XXX */
91063ecc40cSmaxv 			}
91163ecc40cSmaxv 		}
91263ecc40cSmaxv 		if (laddr == NULL) {
91363ecc40cSmaxv 			if (error == 0)
91463ecc40cSmaxv 				error = EADDRNOTAVAIL;
91563ecc40cSmaxv 			goto release;
91663ecc40cSmaxv 		}
9170e390eeeSozaki-r 		if (inp->inp_lport == 0) {
91863ecc40cSmaxv 			/*
91963ecc40cSmaxv 			 * Craft a sockaddr_in6 for the local endpoint. Use the
92063ecc40cSmaxv 			 * "any" as a base, set the address, and recover the
92163ecc40cSmaxv 			 * scope.
92263ecc40cSmaxv 			 */
92363ecc40cSmaxv 			struct sockaddr_in6 lsin6 =
9240e390eeeSozaki-r 			    *((const struct sockaddr_in6 *)inp->inp_socket->so_proto->pr_domain->dom_sa_any);
92563ecc40cSmaxv 			lsin6.sin6_addr = *laddr;
92663ecc40cSmaxv 			error = sa6_recoverscope(&lsin6);
92763ecc40cSmaxv 			if (error)
92863ecc40cSmaxv 				goto release;
92963ecc40cSmaxv 
930b000e63fSozaki-r 			error = in6pcb_set_port(&lsin6, inp, l);
93163ecc40cSmaxv 
93263ecc40cSmaxv 			if (error) {
933a071c829Sozaki-r 				in6p_laddr(inp) = in6addr_any;
93463ecc40cSmaxv 				goto release;
93563ecc40cSmaxv 			}
93663ecc40cSmaxv 		}
93763ecc40cSmaxv 	} else {
938a071c829Sozaki-r 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp))) {
93963ecc40cSmaxv 			error = ENOTCONN;
94063ecc40cSmaxv 			goto release;
94163ecc40cSmaxv 		}
942a071c829Sozaki-r 		if (IN6_IS_ADDR_V4MAPPED(&in6p_faddr(inp))) {
9430e390eeeSozaki-r 			if ((inp->inp_flags & IN6P_IPV6_V6ONLY))
94463ecc40cSmaxv 			{
94563ecc40cSmaxv 				/*
94663ecc40cSmaxv 				 * XXX: this case would happen when the
94763ecc40cSmaxv 				 * application sets the V6ONLY flag after
94863ecc40cSmaxv 				 * connecting the foreign address.
94963ecc40cSmaxv 				 * Such applications should be fixed,
95063ecc40cSmaxv 				 * so we bark here.
95163ecc40cSmaxv 				 */
95263ecc40cSmaxv 				log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
95363ecc40cSmaxv 				    "option was set for a connected socket\n");
95463ecc40cSmaxv 				error = EINVAL;
95563ecc40cSmaxv 				goto release;
95663ecc40cSmaxv 			} else
95763ecc40cSmaxv 				af = AF_INET;
95863ecc40cSmaxv 		}
959a071c829Sozaki-r 		laddr = &in6p_laddr(inp);
960a071c829Sozaki-r 		faddr = &in6p_faddr(inp);
9610e390eeeSozaki-r 		fport = inp->inp_fport;
96263ecc40cSmaxv 	}
96363ecc40cSmaxv 
96463ecc40cSmaxv 	if (af == AF_INET)
96563ecc40cSmaxv 		hlen = sizeof(struct ip);
96663ecc40cSmaxv 
96763ecc40cSmaxv 	/*
96863ecc40cSmaxv 	 * Calculate data length and get a mbuf
96963ecc40cSmaxv 	 * for UDP and IP6 headers.
97063ecc40cSmaxv 	 */
97163ecc40cSmaxv 	M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
97263ecc40cSmaxv 	if (m == NULL) {
97363ecc40cSmaxv 		error = ENOBUFS;
97463ecc40cSmaxv 		goto release;
97563ecc40cSmaxv 	}
97663ecc40cSmaxv 
97763ecc40cSmaxv 	/*
97863ecc40cSmaxv 	 * Stuff checksum and output datagram.
97963ecc40cSmaxv 	 */
98063ecc40cSmaxv 	udp6 = (struct udphdr *)(mtod(m, char *) + hlen);
9810e390eeeSozaki-r 	udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */
98263ecc40cSmaxv 	udp6->uh_dport = fport;
98363ecc40cSmaxv 	if (plen <= 0xffff)
98463ecc40cSmaxv 		udp6->uh_ulen = htons((u_int16_t)plen);
98563ecc40cSmaxv 	else
98663ecc40cSmaxv 		udp6->uh_ulen = 0;
98763ecc40cSmaxv 	udp6->uh_sum = 0;
98863ecc40cSmaxv 
98963ecc40cSmaxv 	switch (af) {
99063ecc40cSmaxv 	case AF_INET6:
99163ecc40cSmaxv 		ip6 = mtod(m, struct ip6_hdr *);
992a071c829Sozaki-r 		ip6->ip6_flow	= in6p_flowinfo(inp) & IPV6_FLOWINFO_MASK;
99363ecc40cSmaxv 		ip6->ip6_vfc 	&= ~IPV6_VERSION_MASK;
99463ecc40cSmaxv 		ip6->ip6_vfc 	|= IPV6_VERSION;
99563ecc40cSmaxv #if 0		/* ip6_plen will be filled in ip6_output. */
99663ecc40cSmaxv 		ip6->ip6_plen	= htons((u_int16_t)plen);
99763ecc40cSmaxv #endif
99863ecc40cSmaxv 		ip6->ip6_nxt	= IPPROTO_UDP;
999b000e63fSozaki-r 		ip6->ip6_hlim	= in6pcb_selecthlim_rt(inp);
100063ecc40cSmaxv 		ip6->ip6_src	= *laddr;
100163ecc40cSmaxv 		ip6->ip6_dst	= *faddr;
100263ecc40cSmaxv 
100363ecc40cSmaxv 		udp6->uh_sum = in6_cksum_phdr(laddr, faddr,
100463ecc40cSmaxv 		    htonl(plen), htonl(IPPROTO_UDP));
100563ecc40cSmaxv 		m->m_pkthdr.csum_flags = M_CSUM_UDPv6;
100663ecc40cSmaxv 		m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
100763ecc40cSmaxv 
100863ecc40cSmaxv 		UDP6_STATINC(UDP6_STAT_OPACKETS);
10090e390eeeSozaki-r 		error = ip6_output(m, optp, &inp->inp_route, 0,
1010a071c829Sozaki-r 		    in6p_moptions(inp), inp, NULL);
101163ecc40cSmaxv 		break;
101263ecc40cSmaxv 	case AF_INET:
101363ecc40cSmaxv #ifdef INET
101463ecc40cSmaxv 		/* can't transmit jumbogram over IPv4 */
101563ecc40cSmaxv 		if (plen > 0xffff) {
101663ecc40cSmaxv 			error = EMSGSIZE;
101763ecc40cSmaxv 			goto release;
101863ecc40cSmaxv 		}
101963ecc40cSmaxv 
102063ecc40cSmaxv 		ip = mtod(m, struct ip *);
102163ecc40cSmaxv 		ui = (struct udpiphdr *)ip;
102263ecc40cSmaxv 		memset(ui->ui_x1, 0, sizeof(ui->ui_x1));
102363ecc40cSmaxv 		ui->ui_pr = IPPROTO_UDP;
102463ecc40cSmaxv 		ui->ui_len = htons(plen);
102563ecc40cSmaxv 		memcpy(&ui->ui_src, &laddr->s6_addr[12], sizeof(ui->ui_src));
102663ecc40cSmaxv 		ui->ui_ulen = ui->ui_len;
102763ecc40cSmaxv 
10280e390eeeSozaki-r 		flags = (inp->inp_socket->so_options &
102963ecc40cSmaxv 			 (SO_DONTROUTE | SO_BROADCAST));
103063ecc40cSmaxv 		memcpy(&ui->ui_dst, &faddr->s6_addr[12], sizeof(ui->ui_dst));
103163ecc40cSmaxv 
103263ecc40cSmaxv 		udp6->uh_sum = in_cksum(m, hlen + plen);
103363ecc40cSmaxv 		if (udp6->uh_sum == 0)
103463ecc40cSmaxv 			udp6->uh_sum = 0xffff;
103563ecc40cSmaxv 
103663ecc40cSmaxv 		ip->ip_len = htons(hlen + plen);
1037b000e63fSozaki-r 		ip->ip_ttl = in6pcb_selecthlim(inp, NULL); /* XXX */
103863ecc40cSmaxv 		ip->ip_tos = 0;	/* XXX */
103963ecc40cSmaxv 
104063ecc40cSmaxv 		UDP_STATINC(UDP_STAT_OPACKETS);
10410e390eeeSozaki-r 		error = ip_output(m, NULL, &inp->inp_route, flags /* XXX */,
10420e390eeeSozaki-r 		    inp->inp_moptions, NULL);
104363ecc40cSmaxv 		break;
104463ecc40cSmaxv #else
104563ecc40cSmaxv 		error = EAFNOSUPPORT;
104663ecc40cSmaxv 		goto release;
104763ecc40cSmaxv #endif
104863ecc40cSmaxv 	}
104963ecc40cSmaxv 	goto releaseopt;
105063ecc40cSmaxv 
105163ecc40cSmaxv release:
105263ecc40cSmaxv 	m_freem(m);
105363ecc40cSmaxv 
105463ecc40cSmaxv releaseopt:
105563ecc40cSmaxv 	if (control) {
105663ecc40cSmaxv 		if (optp == &opt)
105763ecc40cSmaxv 			ip6_clearpktopts(&opt, -1);
105863ecc40cSmaxv 		m_freem(control);
105963ecc40cSmaxv 	}
106063ecc40cSmaxv 	return (error);
106163ecc40cSmaxv }
106263ecc40cSmaxv 
10634ae03c18Srmind static int
10644ae03c18Srmind udp6_attach(struct socket *so, int proto)
10654ae03c18Srmind {
10660e390eeeSozaki-r 	struct inpcb *inp;
10674ae03c18Srmind 	int s, error;
10684ae03c18Srmind 
10690e390eeeSozaki-r 	KASSERT(sotoinpcb(so) == NULL);
10704ae03c18Srmind 	sosetlock(so);
10714ae03c18Srmind 
1072fa4f0f36Smaxv 	error = soreserve(so, udp6_sendspace, udp6_recvspace);
1073fa4f0f36Smaxv 	if (error) {
1074fa4f0f36Smaxv 		return error;
1075fa4f0f36Smaxv 	}
1076fa4f0f36Smaxv 
10774ae03c18Srmind 	/*
10784ae03c18Srmind 	 * MAPPED_ADDR implementation spec:
10794ae03c18Srmind 	 *  Always attach for IPv6, and only when necessary for IPv4.
10804ae03c18Srmind 	 */
10814ae03c18Srmind 	s = splsoftnet();
10822ba9f052Sozaki-r 	error = inpcb_create(so, &udbtable);
10834ae03c18Srmind 	splx(s);
10844ae03c18Srmind 	if (error) {
10854ae03c18Srmind 		return error;
10864ae03c18Srmind 	}
1087fa4f0f36Smaxv 
10880e390eeeSozaki-r 	inp = sotoinpcb(so);
1089a071c829Sozaki-r 	in6p_cksum(inp) = -1;	/* just to be sure */
10904ae03c18Srmind 
10914ae03c18Srmind 	KASSERT(solocked(so));
10924ae03c18Srmind 	return 0;
10934ae03c18Srmind }
10944ae03c18Srmind 
10954ae03c18Srmind static void
10964ae03c18Srmind udp6_detach(struct socket *so)
10974ae03c18Srmind {
10980e390eeeSozaki-r 	struct inpcb *inp = sotoinpcb(so);
10994ae03c18Srmind 	int s;
11004ae03c18Srmind 
11014ae03c18Srmind 	KASSERT(solocked(so));
11020e390eeeSozaki-r 	KASSERT(inp != NULL);
11034ae03c18Srmind 
11044ae03c18Srmind 	s = splsoftnet();
11052ba9f052Sozaki-r 	inpcb_destroy(inp);
11064ae03c18Srmind 	splx(s);
11074ae03c18Srmind }
11084ae03c18Srmind 
1109d54d7ab2Srtr static int
1110eddf3af3Srtr udp6_accept(struct socket *so, struct sockaddr *nam)
1111d27b133dSrtr {
1112d27b133dSrtr 	KASSERT(solocked(so));
1113d27b133dSrtr 
1114d27b133dSrtr 	return EOPNOTSUPP;
1115d27b133dSrtr }
1116d27b133dSrtr 
1117d27b133dSrtr static int
1118a2ba5e69Srtr udp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
11196dd8eef0Srtr {
11200e390eeeSozaki-r 	struct inpcb *inp = sotoinpcb(so);
1121a2ba5e69Srtr 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
11226dd8eef0Srtr 	int error = 0;
11236dd8eef0Srtr 	int s;
11246dd8eef0Srtr 
11256dd8eef0Srtr 	KASSERT(solocked(so));
11260e390eeeSozaki-r 	KASSERT(inp != NULL);
11276dd8eef0Srtr 
11286dd8eef0Srtr 	s = splsoftnet();
1129b000e63fSozaki-r 	error = in6pcb_bind(inp, sin6, l);
11306dd8eef0Srtr 	splx(s);
11316dd8eef0Srtr 	return error;
11326dd8eef0Srtr }
11336dd8eef0Srtr 
11346dd8eef0Srtr static int
1135ce6a5ff6Srtr udp6_listen(struct socket *so, struct lwp *l)
11366dd8eef0Srtr {
11376dd8eef0Srtr 	KASSERT(solocked(so));
11386dd8eef0Srtr 
11396dd8eef0Srtr 	return EOPNOTSUPP;
11406dd8eef0Srtr }
11416dd8eef0Srtr 
11426dd8eef0Srtr static int
1143fd12cf39Srtr udp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
1144ad6ae402Srtr {
11450e390eeeSozaki-r 	struct inpcb *inp = sotoinpcb(so);
1146ad6ae402Srtr 	int error = 0;
1147ad6ae402Srtr 	int s;
1148ad6ae402Srtr 
1149ad6ae402Srtr 	KASSERT(solocked(so));
11500e390eeeSozaki-r 	KASSERT(inp != NULL);
1151ad6ae402Srtr 
1152a071c829Sozaki-r 	if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp)))
1153ad6ae402Srtr 		return EISCONN;
1154ad6ae402Srtr 	s = splsoftnet();
1155b000e63fSozaki-r 	error = in6pcb_connect(inp, (struct sockaddr_in6 *)nam, l);
1156ad6ae402Srtr 	splx(s);
1157ad6ae402Srtr 	if (error == 0)
1158ad6ae402Srtr 		soisconnected(so);
1159ad6ae402Srtr 
1160ad6ae402Srtr 	return error;
1161ad6ae402Srtr }
1162ad6ae402Srtr 
1163ad6ae402Srtr static int
11648cf67cc6Srtr udp6_connect2(struct socket *so, struct socket *so2)
11658cf67cc6Srtr {
11668cf67cc6Srtr 	KASSERT(solocked(so));
11678cf67cc6Srtr 
11688cf67cc6Srtr 	return EOPNOTSUPP;
11698cf67cc6Srtr }
11708cf67cc6Srtr 
11718cf67cc6Srtr static int
1172892163b8Srtr udp6_disconnect(struct socket *so)
1173892163b8Srtr {
11740e390eeeSozaki-r 	struct inpcb *inp = sotoinpcb(so);
1175892163b8Srtr 	int s;
1176892163b8Srtr 
1177892163b8Srtr 	KASSERT(solocked(so));
11780e390eeeSozaki-r 	KASSERT(inp != NULL);
1179892163b8Srtr 
1180a071c829Sozaki-r 	if (IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp)))
1181892163b8Srtr 		return ENOTCONN;
1182892163b8Srtr 
1183892163b8Srtr 	s = splsoftnet();
1184b000e63fSozaki-r 	in6pcb_disconnect(inp);
1185a071c829Sozaki-r 	memset((void *)&in6p_laddr(inp), 0, sizeof(in6p_laddr(inp)));
1186892163b8Srtr 	splx(s);
1187892163b8Srtr 
1188892163b8Srtr 	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
1189b000e63fSozaki-r 	in6pcb_set_state(inp, INP_BOUND);		/* XXX */
1190892163b8Srtr 	return 0;
1191892163b8Srtr }
1192892163b8Srtr 
1193892163b8Srtr static int
1194892163b8Srtr udp6_shutdown(struct socket *so)
1195892163b8Srtr {
1196892163b8Srtr 	int s;
1197892163b8Srtr 
1198892163b8Srtr 	s = splsoftnet();
1199892163b8Srtr 	socantsendmore(so);
1200892163b8Srtr 	splx(s);
1201892163b8Srtr 
1202892163b8Srtr 	return 0;
1203892163b8Srtr }
1204892163b8Srtr 
1205892163b8Srtr static int
1206892163b8Srtr udp6_abort(struct socket *so)
1207892163b8Srtr {
1208892163b8Srtr 	int s;
1209892163b8Srtr 
1210892163b8Srtr 	KASSERT(solocked(so));
12110e390eeeSozaki-r 	KASSERT(sotoinpcb(so) != NULL);
1212892163b8Srtr 
1213892163b8Srtr 	s = splsoftnet();
1214892163b8Srtr 	soisdisconnected(so);
12152ba9f052Sozaki-r 	inpcb_destroy(sotoinpcb(so));
1216892163b8Srtr 	splx(s);
1217892163b8Srtr 
1218892163b8Srtr 	return 0;
1219892163b8Srtr }
1220892163b8Srtr 
1221892163b8Srtr static int
12220dedd977Srtr udp6_ioctl(struct socket *so, u_long cmd, void *addr6, struct ifnet *ifp)
122374d3c214Sitojun {
122474d3c214Sitojun 	/*
122574d3c214Sitojun 	 * MAPPED_ADDR implementation info:
122674d3c214Sitojun 	 *  Mapped addr support for PRU_CONTROL is not necessary.
122774d3c214Sitojun 	 *  Because typical user of PRU_CONTROL is such as ifconfig,
122874d3c214Sitojun 	 *  and they don't associate any addr to their socket.  Then
122974d3c214Sitojun 	 *  socket family is only hint about the PRU_CONTROL'ed address
123074d3c214Sitojun 	 *  family, especially when getting addrs from kernel.
123174d3c214Sitojun 	 *  So AF_INET socket need to be used to control AF_INET addrs,
123274d3c214Sitojun 	 *  and AF_INET6 socket for AF_INET6 addrs.
123374d3c214Sitojun 	 */
12340dedd977Srtr 	return in6_control(so, cmd, addr6, ifp);
12354ae03c18Srmind }
1236d54d7ab2Srtr 
1237a60320caSrtr static int
1238a60320caSrtr udp6_stat(struct socket *so, struct stat *ub)
1239a60320caSrtr {
1240ff90c29dSrtr 	KASSERT(solocked(so));
1241ff90c29dSrtr 
1242909a1fc6Srtr 	/* stat: don't bother with a blocksize */
1243909a1fc6Srtr 	return 0;
1244a60320caSrtr }
1245a60320caSrtr 
1246d575eb54Srtr static int
1247eddf3af3Srtr udp6_peeraddr(struct socket *so, struct sockaddr *nam)
1248d575eb54Srtr {
1249d575eb54Srtr 	KASSERT(solocked(so));
12500e390eeeSozaki-r 	KASSERT(sotoinpcb(so) != NULL);
1251d575eb54Srtr 	KASSERT(nam != NULL);
1252d575eb54Srtr 
1253b000e63fSozaki-r 	in6pcb_fetch_peeraddr(sotoinpcb(so), (struct sockaddr_in6 *)nam);
1254d575eb54Srtr 	return 0;
1255d575eb54Srtr }
1256d575eb54Srtr 
1257d575eb54Srtr static int
1258eddf3af3Srtr udp6_sockaddr(struct socket *so, struct sockaddr *nam)
1259d575eb54Srtr {
1260d575eb54Srtr 	KASSERT(solocked(so));
12610e390eeeSozaki-r 	KASSERT(sotoinpcb(so) != NULL);
1262d575eb54Srtr 	KASSERT(nam != NULL);
1263d575eb54Srtr 
1264b000e63fSozaki-r 	in6pcb_fetch_sockaddr(sotoinpcb(so), (struct sockaddr_in6 *)nam);
1265d575eb54Srtr 	return 0;
1266d575eb54Srtr }
1267d575eb54Srtr 
126835b22fa9Srtr static int
1269822872eaSrtr udp6_rcvd(struct socket *so, int flags, struct lwp *l)
1270822872eaSrtr {
1271822872eaSrtr 	KASSERT(solocked(so));
1272822872eaSrtr 
1273822872eaSrtr 	return EOPNOTSUPP;
1274822872eaSrtr }
1275822872eaSrtr 
1276822872eaSrtr static int
127735b22fa9Srtr udp6_recvoob(struct socket *so, struct mbuf *m, int flags)
127835b22fa9Srtr {
127935b22fa9Srtr 	KASSERT(solocked(so));
128035b22fa9Srtr 
128135b22fa9Srtr 	return EOPNOTSUPP;
128235b22fa9Srtr }
128335b22fa9Srtr 
128435b22fa9Srtr static int
1285fd12cf39Srtr udp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
1286651e5bd3Srtr     struct mbuf *control, struct lwp *l)
1287651e5bd3Srtr {
12880e390eeeSozaki-r 	struct inpcb *inp = sotoinpcb(so);
1289651e5bd3Srtr 	int error = 0;
1290651e5bd3Srtr 	int s;
1291651e5bd3Srtr 
1292651e5bd3Srtr 	KASSERT(solocked(so));
12930e390eeeSozaki-r 	KASSERT(inp != NULL);
1294651e5bd3Srtr 	KASSERT(m != NULL);
1295651e5bd3Srtr 
1296651e5bd3Srtr 	s = splsoftnet();
12970e390eeeSozaki-r 	error = udp6_output(inp, m, (struct sockaddr_in6 *)nam, control, l);
1298651e5bd3Srtr 	splx(s);
1299651e5bd3Srtr 
1300651e5bd3Srtr 	return error;
1301651e5bd3Srtr }
1302651e5bd3Srtr 
1303651e5bd3Srtr static int
130435b22fa9Srtr udp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
130535b22fa9Srtr {
130635b22fa9Srtr 	KASSERT(solocked(so));
130735b22fa9Srtr 
130835b22fa9Srtr 	m_freem(m);
130935b22fa9Srtr 	m_freem(control);
131035b22fa9Srtr 
131135b22fa9Srtr 	return EOPNOTSUPP;
131235b22fa9Srtr }
131335b22fa9Srtr 
13148cf67cc6Srtr static int
13158cf67cc6Srtr udp6_purgeif(struct socket *so, struct ifnet *ifp)
13168cf67cc6Srtr {
13178cf67cc6Srtr 
13188cf67cc6Srtr 	mutex_enter(softnet_lock);
1319b000e63fSozaki-r 	in6pcb_purgeif0(&udbtable, ifp);
13209e8d969cSozaki-r #ifdef NET_MPSAFE
13218cf67cc6Srtr 	mutex_exit(softnet_lock);
13222526d8f6Sknakahara #endif
13239e8d969cSozaki-r 	in6_purgeif(ifp);
13249e8d969cSozaki-r #ifdef NET_MPSAFE
13259e8d969cSozaki-r 	mutex_enter(softnet_lock);
13269e8d969cSozaki-r #endif
1327b000e63fSozaki-r 	in6pcb_purgeif(&udbtable, ifp);
13289e8d969cSozaki-r 	mutex_exit(softnet_lock);
13298cf67cc6Srtr 
13308cf67cc6Srtr 	return 0;
13318cf67cc6Srtr }
13328cf67cc6Srtr 
1333c2da059bSthorpej static int
1334c2da059bSthorpej sysctl_net_inet6_udp6_stats(SYSCTLFN_ARGS)
1335c2da059bSthorpej {
1336c2da059bSthorpej 
1337b129a80cSthorpej 	return (NETSTAT_SYSCTL(udp6stat_percpu, UDP6_NSTATS));
1338c2da059bSthorpej }
1339c2da059bSthorpej 
134011281f01Spooka static void
134111281f01Spooka sysctl_net_inet6_udp6_setup(struct sysctllog **clog)
134274d3c214Sitojun {
13434f6fb3bfSpooka 
134419af35fdSatatat 	sysctl_createv(clog, 0, NULL, NULL,
134519af35fdSatatat 		       CTLFLAG_PERMANENT,
134613f8d2ceSatatat 		       CTLTYPE_NODE, "inet6", NULL,
134713f8d2ceSatatat 		       NULL, 0, NULL, 0,
134813f8d2ceSatatat 		       CTL_NET, PF_INET6, CTL_EOL);
134919af35fdSatatat 	sysctl_createv(clog, 0, NULL, NULL,
135019af35fdSatatat 		       CTLFLAG_PERMANENT,
13514de3747bSatatat 		       CTLTYPE_NODE, "udp6",
13524de3747bSatatat 		       SYSCTL_DESCR("UDPv6 related settings"),
135313f8d2ceSatatat 		       NULL, 0, NULL, 0,
135413f8d2ceSatatat 		       CTL_NET, PF_INET6, IPPROTO_UDP, CTL_EOL);
135574d3c214Sitojun 
135619af35fdSatatat 	sysctl_createv(clog, 0, NULL, NULL,
135719af35fdSatatat 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
13584de3747bSatatat 		       CTLTYPE_INT, "sendspace",
13594de3747bSatatat 		       SYSCTL_DESCR("Default UDP send buffer size"),
136013f8d2ceSatatat 		       NULL, 0, &udp6_sendspace, 0,
136113f8d2ceSatatat 		       CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_SENDSPACE,
136213f8d2ceSatatat 		       CTL_EOL);
136319af35fdSatatat 	sysctl_createv(clog, 0, NULL, NULL,
136419af35fdSatatat 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
13654de3747bSatatat 		       CTLTYPE_INT, "recvspace",
13664de3747bSatatat 		       SYSCTL_DESCR("Default UDP receive buffer size"),
136713f8d2ceSatatat 		       NULL, 0, &udp6_recvspace, 0,
136813f8d2ceSatatat 		       CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_RECVSPACE,
136913f8d2ceSatatat 		       CTL_EOL);
13707994b6f9Sthorpej 	sysctl_createv(clog, 0, NULL, NULL,
13717994b6f9Sthorpej 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
13727994b6f9Sthorpej 		       CTLTYPE_INT, "do_loopback_cksum",
13737994b6f9Sthorpej 		       SYSCTL_DESCR("Perform UDP checksum on loopback"),
13747994b6f9Sthorpej 		       NULL, 0, &udp_do_loopback_cksum, 0,
13757994b6f9Sthorpej 		       CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_LOOPBACKCKSUM,
13767994b6f9Sthorpej 		       CTL_EOL);
13777c62c74dSatatat 	sysctl_createv(clog, 0, NULL, NULL,
13787c62c74dSatatat 		       CTLFLAG_PERMANENT,
13795b8a6c91Satatat 		       CTLTYPE_STRUCT, "pcblist",
13807c62c74dSatatat 		       SYSCTL_DESCR("UDP protocol control block list"),
13817c62c74dSatatat 		       sysctl_inpcblist, 0, &udbtable, 0,
13827c62c74dSatatat 		       CTL_NET, PF_INET6, IPPROTO_UDP, CTL_CREATE,
13837c62c74dSatatat 		       CTL_EOL);
1384151760f5Srpaulo 	sysctl_createv(clog, 0, NULL, NULL,
1385151760f5Srpaulo 		       CTLFLAG_PERMANENT,
1386151760f5Srpaulo 		       CTLTYPE_STRUCT, "stats",
1387151760f5Srpaulo 		       SYSCTL_DESCR("UDPv6 statistics"),
1388c2da059bSthorpej 		       sysctl_net_inet6_udp6_stats, 0, NULL, 0,
1389151760f5Srpaulo 		       CTL_NET, PF_INET6, IPPROTO_UDP, UDP6CTL_STATS,
1390151760f5Srpaulo 		       CTL_EOL);
139174d3c214Sitojun }
1392c2da059bSthorpej 
1393c2da059bSthorpej void
1394c2da059bSthorpej udp6_statinc(u_int stat)
1395c2da059bSthorpej {
1396c2da059bSthorpej 
1397c2da059bSthorpej 	KASSERT(stat < UDP6_NSTATS);
1398c2da059bSthorpej 	UDP6_STATINC(stat);
1399c2da059bSthorpej }
140039bd8deeSrmind 
1401890dda53Sknakahara #ifdef IPSEC
1402890dda53Sknakahara /*
1403890dda53Sknakahara  * Returns:
1404890dda53Sknakahara  *     1 if the packet was processed
1405890dda53Sknakahara  *     0 if normal UDP processing should take place
1406890dda53Sknakahara  *    -1 if an error occurred and m was freed
1407890dda53Sknakahara  */
1408890dda53Sknakahara static int
1409b9e11ce7Smaxv udp6_espinudp(struct mbuf **mp, int off)
1410890dda53Sknakahara {
1411890dda53Sknakahara 	const size_t skip = sizeof(struct udphdr);
1412890dda53Sknakahara 	size_t len;
1413890dda53Sknakahara 	void *data;
1414890dda53Sknakahara 	size_t minlen;
1415890dda53Sknakahara 	int ip6hdrlen;
1416890dda53Sknakahara 	struct ip6_hdr *ip6;
1417890dda53Sknakahara 	struct m_tag *tag;
1418890dda53Sknakahara 	struct udphdr *udphdr;
1419890dda53Sknakahara 	u_int16_t sport, dport;
1420890dda53Sknakahara 	struct mbuf *m = *mp;
1421890dda53Sknakahara 	uint32_t *marker;
1422890dda53Sknakahara 
1423890dda53Sknakahara 	/*
1424890dda53Sknakahara 	 * Collapse the mbuf chain if the first mbuf is too short
1425890dda53Sknakahara 	 * The longest case is: UDP + non ESP marker + ESP
1426890dda53Sknakahara 	 */
1427890dda53Sknakahara 	minlen = off + sizeof(u_int64_t) + sizeof(struct esp);
1428890dda53Sknakahara 	if (minlen > m->m_pkthdr.len)
1429890dda53Sknakahara 		minlen = m->m_pkthdr.len;
1430890dda53Sknakahara 
1431890dda53Sknakahara 	if (m->m_len < minlen) {
1432890dda53Sknakahara 		if ((*mp = m_pullup(m, minlen)) == NULL) {
1433*5d781b6fSriastradh 			return -1; /* dropped */
1434890dda53Sknakahara 		}
1435890dda53Sknakahara 		m = *mp;
1436890dda53Sknakahara 	}
1437890dda53Sknakahara 
1438890dda53Sknakahara 	len = m->m_len - off;
1439890dda53Sknakahara 	data = mtod(m, char *) + off;
1440890dda53Sknakahara 
1441890dda53Sknakahara 	/* Ignore keepalive packets */
1442890dda53Sknakahara 	if ((len == 1) && (*(unsigned char *)data == 0xff)) {
1443890dda53Sknakahara 		m_freem(m);
1444890dda53Sknakahara 		*mp = NULL; /* avoid any further processing by caller ... */
1445*5d781b6fSriastradh 		return 1;	/* consumed */
1446890dda53Sknakahara 	}
1447890dda53Sknakahara 
1448890dda53Sknakahara 	/* Handle Non-ESP marker (32bit). If zero, then IKE. */
1449890dda53Sknakahara 	marker = (uint32_t *)data;
1450890dda53Sknakahara 	if (len <= sizeof(uint32_t))
1451*5d781b6fSriastradh 		return 0;	/* passthrough */
1452890dda53Sknakahara 	if (marker[0] == 0)
1453*5d781b6fSriastradh 		return 0;	/* passthrough */
1454890dda53Sknakahara 
1455890dda53Sknakahara 	/*
1456890dda53Sknakahara 	 * Get the UDP ports. They are handled in network
1457890dda53Sknakahara 	 * order everywhere in IPSEC_NAT_T code.
1458890dda53Sknakahara 	 */
1459890dda53Sknakahara 	udphdr = (struct udphdr *)((char *)data - skip);
1460890dda53Sknakahara 	sport = udphdr->uh_sport;
1461890dda53Sknakahara 	dport = udphdr->uh_dport;
1462890dda53Sknakahara 
1463890dda53Sknakahara 	/*
1464890dda53Sknakahara 	 * Remove the UDP header (and possibly the non ESP marker)
1465890dda53Sknakahara 	 * IPv6 header length is ip6hdrlen
1466890dda53Sknakahara 	 * Before:
1467890dda53Sknakahara 	 *   <---- off --->
1468890dda53Sknakahara 	 *   +-----+------+-----+
1469890dda53Sknakahara 	 *   | IP6 |  UDP | ESP |
1470890dda53Sknakahara 	 *   +-----+------+-----+
1471890dda53Sknakahara 	 *         <-skip->
1472890dda53Sknakahara 	 * After:
1473890dda53Sknakahara 	 *          +-----+-----+
1474890dda53Sknakahara 	 *          | IP6 | ESP |
1475890dda53Sknakahara 	 *          +-----+-----+
1476890dda53Sknakahara 	 *   <-skip->
1477890dda53Sknakahara 	 */
1478890dda53Sknakahara 	ip6hdrlen = off - sizeof(struct udphdr);
1479890dda53Sknakahara 	memmove(mtod(m, char *) + skip, mtod(m, void *), ip6hdrlen);
1480890dda53Sknakahara 	m_adj(m, skip);
1481890dda53Sknakahara 
1482890dda53Sknakahara 	ip6 = mtod(m, struct ip6_hdr *);
1483890dda53Sknakahara 	ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - skip);
1484890dda53Sknakahara 	ip6->ip6_nxt = IPPROTO_ESP;
1485890dda53Sknakahara 
1486890dda53Sknakahara 	/*
1487890dda53Sknakahara 	 * We have modified the packet - it is now ESP, so we should not
1488890dda53Sknakahara 	 * return to UDP processing ...
1489890dda53Sknakahara 	 *
1490890dda53Sknakahara 	 * Add a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
1491890dda53Sknakahara 	 * the source UDP port. This is required if we want
1492890dda53Sknakahara 	 * to select the right SPD for multiple hosts behind
1493890dda53Sknakahara 	 * same NAT
1494890dda53Sknakahara 	 */
1495890dda53Sknakahara 	if ((tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
1496890dda53Sknakahara 	    sizeof(sport) + sizeof(dport), M_DONTWAIT)) == NULL) {
1497890dda53Sknakahara 		m_freem(m);
1498*5d781b6fSriastradh 		*mp = NULL;
1499*5d781b6fSriastradh 		return -1;	/* dropped */
1500890dda53Sknakahara 	}
1501890dda53Sknakahara 	((u_int16_t *)(tag + 1))[0] = sport;
1502890dda53Sknakahara 	((u_int16_t *)(tag + 1))[1] = dport;
1503890dda53Sknakahara 	m_tag_prepend(m, tag);
1504890dda53Sknakahara 
1505890dda53Sknakahara 	if (ipsec_used)
1506890dda53Sknakahara 		ipsec6_common_input(&m, &ip6hdrlen, IPPROTO_ESP);
1507890dda53Sknakahara 	else
1508890dda53Sknakahara 		m_freem(m);
1509890dda53Sknakahara 
1510890dda53Sknakahara 	/* We handled it, it shouldn't be handled by UDP */
1511890dda53Sknakahara 	*mp = NULL; /* avoid free by caller ... */
1512*5d781b6fSriastradh 	return 1;		/* consumed */
1513890dda53Sknakahara }
1514890dda53Sknakahara #endif /* IPSEC */
1515890dda53Sknakahara 
1516e401453fSrmind PR_WRAP_USRREQS(udp6)
1517e401453fSrmind #define	udp6_attach	udp6_attach_wrapper
1518e401453fSrmind #define	udp6_detach	udp6_detach_wrapper
1519d27b133dSrtr #define	udp6_accept	udp6_accept_wrapper
15206dd8eef0Srtr #define	udp6_bind	udp6_bind_wrapper
15216dd8eef0Srtr #define	udp6_listen	udp6_listen_wrapper
1522ad6ae402Srtr #define	udp6_connect	udp6_connect_wrapper
15238cf67cc6Srtr #define	udp6_connect2	udp6_connect2_wrapper
1524892163b8Srtr #define	udp6_disconnect	udp6_disconnect_wrapper
1525892163b8Srtr #define	udp6_shutdown	udp6_shutdown_wrapper
1526892163b8Srtr #define	udp6_abort	udp6_abort_wrapper
1527d54d7ab2Srtr #define	udp6_ioctl	udp6_ioctl_wrapper
1528a60320caSrtr #define	udp6_stat	udp6_stat_wrapper
1529d575eb54Srtr #define	udp6_peeraddr	udp6_peeraddr_wrapper
1530d575eb54Srtr #define	udp6_sockaddr	udp6_sockaddr_wrapper
1531822872eaSrtr #define	udp6_rcvd	udp6_rcvd_wrapper
153235b22fa9Srtr #define	udp6_recvoob	udp6_recvoob_wrapper
1533651e5bd3Srtr #define	udp6_send	udp6_send_wrapper
153435b22fa9Srtr #define	udp6_sendoob	udp6_sendoob_wrapper
15358cf67cc6Srtr #define	udp6_purgeif	udp6_purgeif_wrapper
153639bd8deeSrmind 
153739bd8deeSrmind const struct pr_usrreqs udp6_usrreqs = {
15384ae03c18Srmind 	.pr_attach	= udp6_attach,
15394ae03c18Srmind 	.pr_detach	= udp6_detach,
1540d27b133dSrtr 	.pr_accept	= udp6_accept,
15416dd8eef0Srtr 	.pr_bind	= udp6_bind,
15426dd8eef0Srtr 	.pr_listen	= udp6_listen,
1543ad6ae402Srtr 	.pr_connect	= udp6_connect,
15448cf67cc6Srtr 	.pr_connect2	= udp6_connect2,
1545892163b8Srtr 	.pr_disconnect	= udp6_disconnect,
1546892163b8Srtr 	.pr_shutdown	= udp6_shutdown,
1547892163b8Srtr 	.pr_abort	= udp6_abort,
1548d54d7ab2Srtr 	.pr_ioctl	= udp6_ioctl,
1549a60320caSrtr 	.pr_stat	= udp6_stat,
1550d575eb54Srtr 	.pr_peeraddr	= udp6_peeraddr,
1551d575eb54Srtr 	.pr_sockaddr	= udp6_sockaddr,
1552822872eaSrtr 	.pr_rcvd	= udp6_rcvd,
155335b22fa9Srtr 	.pr_recvoob	= udp6_recvoob,
1554651e5bd3Srtr 	.pr_send	= udp6_send,
155535b22fa9Srtr 	.pr_sendoob	= udp6_sendoob,
15568cf67cc6Srtr 	.pr_purgeif	= udp6_purgeif,
155739bd8deeSrmind };
1558