xref: /openbsd-src/sys/netinet6/udp6_output.c (revision ace0f1891f538e34a7abe4c36dddbf6f6515f1bb)
1*ace0f189Sbluhm /*	$OpenBSD: udp6_output.c,v 1.65 2024/04/17 20:48:51 bluhm Exp $	*/
26cb0fb04Sitojun /*	$KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $	*/
39130c231Sitojun 
49130c231Sitojun /*
59130c231Sitojun  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
69130c231Sitojun  * All rights reserved.
79130c231Sitojun  *
89130c231Sitojun  * Redistribution and use in source and binary forms, with or without
99130c231Sitojun  * modification, are permitted provided that the following conditions
109130c231Sitojun  * are met:
119130c231Sitojun  * 1. Redistributions of source code must retain the above copyright
129130c231Sitojun  *    notice, this list of conditions and the following disclaimer.
139130c231Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
149130c231Sitojun  *    notice, this list of conditions and the following disclaimer in the
159130c231Sitojun  *    documentation and/or other materials provided with the distribution.
169130c231Sitojun  * 3. Neither the name of the project nor the names of its contributors
179130c231Sitojun  *    may be used to endorse or promote products derived from this software
189130c231Sitojun  *    without specific prior written permission.
199130c231Sitojun  *
209130c231Sitojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
219130c231Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229130c231Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239130c231Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
249130c231Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259130c231Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269130c231Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279130c231Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289130c231Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299130c231Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309130c231Sitojun  * SUCH DAMAGE.
319130c231Sitojun  */
329130c231Sitojun 
339130c231Sitojun /*
349130c231Sitojun  * Copyright (c) 1982, 1986, 1989, 1993
359130c231Sitojun  *	The Regents of the University of California.  All rights reserved.
369130c231Sitojun  *
379130c231Sitojun  * Redistribution and use in source and binary forms, with or without
389130c231Sitojun  * modification, are permitted provided that the following conditions
399130c231Sitojun  * are met:
409130c231Sitojun  * 1. Redistributions of source code must retain the above copyright
419130c231Sitojun  *    notice, this list of conditions and the following disclaimer.
429130c231Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
439130c231Sitojun  *    notice, this list of conditions and the following disclaimer in the
449130c231Sitojun  *    documentation and/or other materials provided with the distribution.
4529295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
469130c231Sitojun  *    may be used to endorse or promote products derived from this software
479130c231Sitojun  *    without specific prior written permission.
489130c231Sitojun  *
499130c231Sitojun  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
509130c231Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
519130c231Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
529130c231Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
539130c231Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
549130c231Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
559130c231Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
569130c231Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
579130c231Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
589130c231Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
599130c231Sitojun  * SUCH DAMAGE.
609130c231Sitojun  */
619130c231Sitojun 
6254c5291fSbluhm #include "pf.h"
6354c5291fSbluhm 
649130c231Sitojun #include <sys/param.h>
659130c231Sitojun #include <sys/mbuf.h>
669130c231Sitojun #include <sys/socket.h>
679130c231Sitojun #include <sys/socketvar.h>
689130c231Sitojun #include <sys/errno.h>
699130c231Sitojun #include <sys/stat.h>
709130c231Sitojun #include <sys/systm.h>
719130c231Sitojun #include <sys/syslog.h>
729130c231Sitojun 
739130c231Sitojun #include <net/if.h>
740deb6685Smpi #include <net/if_var.h>
759130c231Sitojun #include <net/route.h>
760e560947Sbluhm #if NPF > 0
770e560947Sbluhm #include <net/pfvar.h>
780e560947Sbluhm #endif
799130c231Sitojun 
809130c231Sitojun #include <netinet/in.h>
81dc572864Sbluhm #include <netinet6/in6_var.h>
829130c231Sitojun #include <netinet/ip.h>
839130c231Sitojun #include <netinet/ip_var.h>
849130c231Sitojun #include <netinet/in_pcb.h>
859130c231Sitojun #include <netinet/udp.h>
869130c231Sitojun #include <netinet/udp_var.h>
879130c231Sitojun #include <netinet/ip6.h>
889130c231Sitojun #include <netinet6/ip6_var.h>
899130c231Sitojun #include <netinet/icmp6.h>
909130c231Sitojun 
919130c231Sitojun /*
92678831beSjsg  * UDP protocol implementation.
939130c231Sitojun  * Per RFC 768, August, 1980.
949130c231Sitojun  */
959130c231Sitojun int
udp6_output(struct inpcb * inp,struct mbuf * m,struct mbuf * addr6,struct mbuf * control)96921ffa12Sbluhm udp6_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr6,
97ee37ea65Smcbride 	struct mbuf *control)
989130c231Sitojun {
996cb0fb04Sitojun 	u_int32_t ulen = m->m_pkthdr.len;
1009130c231Sitojun 	u_int32_t plen = sizeof(struct udphdr) + ulen;
101ed520e16Sjca 	int error = 0, priv = 0, hlen, flags;
1029130c231Sitojun 	struct ip6_hdr *ip6;
1039130c231Sitojun 	struct udphdr *udp6;
104cff23a6bSbluhm 	const struct in6_addr *laddr, *faddr;
1056b532452Sitojun 	struct ip6_pktopts *optp, opt;
106b23e58bbSvgross 	struct sockaddr_in6 tmp, valid;
107942c644cSitojun 	struct proc *p = curproc;	/* XXX */
1080628b56fSderaadt 	u_short fport;
1099130c231Sitojun 
110921ffa12Sbluhm 	if ((inp->inp_socket->so_state & SS_PRIV) != 0)
1119130c231Sitojun 		priv = 1;
1129130c231Sitojun 	if (control) {
1136b532452Sitojun 		if ((error = ip6_setpktopts(control, &opt,
114921ffa12Sbluhm 		    inp->inp_outputopts6, priv, IPPROTO_UDP)) != 0)
1159130c231Sitojun 			goto release;
1166b532452Sitojun 		optp = &opt;
1176b532452Sitojun 	} else
118921ffa12Sbluhm 		optp = inp->inp_outputopts6;
1199130c231Sitojun 
1209130c231Sitojun 	if (addr6) {
121b2a698eaSbluhm 		struct sockaddr_in6 *sin6;
1229130c231Sitojun 
123b2a698eaSbluhm 		if ((error = in6_nam2sin6(addr6, &sin6)))
1249130c231Sitojun 			goto release;
1259130c231Sitojun 		if (sin6->sin6_port == 0) {
1269130c231Sitojun 			error = EADDRNOTAVAIL;
1279130c231Sitojun 			goto release;
1289130c231Sitojun 		}
129ed520e16Sjca 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1301a74d1f7Sbluhm 			error = EADDRNOTAVAIL;
131ed520e16Sjca 			goto release;
132ed520e16Sjca 		}
133921ffa12Sbluhm 		if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
1349130c231Sitojun 			error = EISCONN;
1359130c231Sitojun 			goto release;
1369130c231Sitojun 		}
1379130c231Sitojun 
1389130c231Sitojun 		/* protect *sin6 from overwrites */
1399130c231Sitojun 		tmp = *sin6;
1409130c231Sitojun 		sin6 = &tmp;
1419130c231Sitojun 
1429130c231Sitojun 		faddr = &sin6->sin6_addr;
1439130c231Sitojun 		fport = sin6->sin6_port; /* allow 0 port */
1449130c231Sitojun 
1459130c231Sitojun 		/* KAME hack: embed scopeid */
146952c6363Sbluhm 		if (in6_embedscope(&sin6->sin6_addr, sin6,
147921ffa12Sbluhm 		    inp->inp_outputopts6, inp->inp_moptions6) != 0) {
1489130c231Sitojun 			error = EINVAL;
1499130c231Sitojun 			goto release;
1509130c231Sitojun 		}
1519130c231Sitojun 
152921ffa12Sbluhm 		error = in6_pcbselsrc(&laddr, sin6, inp, optp);
1530039ae51Sjca 		if (error)
1549130c231Sitojun 			goto release;
1550039ae51Sjca 
156921ffa12Sbluhm 		if (inp->inp_lport == 0){
157921ffa12Sbluhm 			error = in_pcbbind(inp, NULL, p);
15805cb8c4fSvgross 			if (error)
1599130c231Sitojun 				goto release;
16005cb8c4fSvgross 		}
1615b750a1dSvgross 
162921ffa12Sbluhm 		if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
163921ffa12Sbluhm 		    !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr)) {
164b23e58bbSvgross 			valid.sin6_addr = *laddr;
165921ffa12Sbluhm 			valid.sin6_port = inp->inp_lport;
166a3324a84Svgross 			valid.sin6_scope_id = 0;
167b23e58bbSvgross 			valid.sin6_family = AF_INET6;
168b23e58bbSvgross 			valid.sin6_len = sizeof(valid);
169921ffa12Sbluhm 			error = in6_pcbaddrisavail(inp, &valid, 0, p);
170b23e58bbSvgross 			if (error)
1715b750a1dSvgross 				goto release;
1725b750a1dSvgross 		}
1739130c231Sitojun 	} else {
174921ffa12Sbluhm 		if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
1759130c231Sitojun 			error = ENOTCONN;
1769130c231Sitojun 			goto release;
1779130c231Sitojun 		}
178921ffa12Sbluhm 		laddr = &inp->inp_laddr6;
179921ffa12Sbluhm 		faddr = &inp->inp_faddr6;
180921ffa12Sbluhm 		fport = inp->inp_fport;
1819130c231Sitojun 	}
1829130c231Sitojun 
1839130c231Sitojun 	hlen = sizeof(struct ip6_hdr);
1849130c231Sitojun 
1859130c231Sitojun 	/*
1869130c231Sitojun 	 * Calculate data length and get a mbuf
1879130c231Sitojun 	 * for UDP and IP6 headers.
1889130c231Sitojun 	 */
1899130c231Sitojun 	M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
19064a3f76cSjsg 	if (m == NULL) {
1919130c231Sitojun 		error = ENOBUFS;
1926280e755Schrisz 		goto releaseopt;
1939130c231Sitojun 	}
1949130c231Sitojun 
1959130c231Sitojun 	/*
1969130c231Sitojun 	 * Stuff checksum and output datagram.
1979130c231Sitojun 	 */
1989130c231Sitojun 	udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
199921ffa12Sbluhm 	udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */
2009130c231Sitojun 	udp6->uh_dport = fport;
2019130c231Sitojun 	if (plen <= 0xffff)
2029130c231Sitojun 		udp6->uh_ulen = htons((u_short)plen);
2039130c231Sitojun 	else
2049130c231Sitojun 		udp6->uh_ulen = 0;
2059130c231Sitojun 	udp6->uh_sum = 0;
2069130c231Sitojun 
2079130c231Sitojun 	ip6 = mtod(m, struct ip6_hdr *);
208921ffa12Sbluhm 	ip6->ip6_flow	= inp->inp_flowinfo & IPV6_FLOWINFO_MASK;
2099130c231Sitojun 	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
2109130c231Sitojun 	ip6->ip6_vfc	|= IPV6_VERSION;
2119130c231Sitojun #if 0	/* ip6_plen will be filled in ip6_output. */
2129130c231Sitojun 	ip6->ip6_plen	= htons((u_short)plen);
2139130c231Sitojun #endif
2149130c231Sitojun 	ip6->ip6_nxt	= IPPROTO_UDP;
215921ffa12Sbluhm 	ip6->ip6_hlim	= in6_selecthlim(inp);
2169130c231Sitojun 	ip6->ip6_src	= *laddr;
2179130c231Sitojun 	ip6->ip6_dst	= *faddr;
2189130c231Sitojun 
219930f66f8Snaddy 	m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
2209130c231Sitojun 
2219130c231Sitojun 	flags = 0;
222921ffa12Sbluhm 	if (inp->inp_flags & IN6P_MINMTU)
2239130c231Sitojun 		flags |= IPV6_MINMTU;
2249130c231Sitojun 
225967e9010Sdlg 	udpstat_inc(udps_opackets);
226ba79ddd5Ssperreault 
2275ee8afe3Smpi 	/* force routing table */
228921ffa12Sbluhm 	m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
229ba79ddd5Ssperreault 
23054c5291fSbluhm #if NPF > 0
231921ffa12Sbluhm 	if (inp->inp_socket->so_state & SS_ISCONNECTED)
232921ffa12Sbluhm 		pf_mbuf_link_inpcb(m, inp);
23354c5291fSbluhm #endif
23454c5291fSbluhm 
23594c0e2bdSbluhm 	error = ip6_output(m, optp, &inp->inp_route,
236*ace0f189Sbluhm 	    flags, inp->inp_moptions6, &inp->inp_seclevel);
2379130c231Sitojun 	goto releaseopt;
2389130c231Sitojun 
2399130c231Sitojun release:
2409130c231Sitojun 	m_freem(m);
2419130c231Sitojun 
2429130c231Sitojun releaseopt:
2439130c231Sitojun 	if (control) {
2446b532452Sitojun 		ip6_clearpktopts(&opt, -1);
2459130c231Sitojun 		m_freem(control);
2469130c231Sitojun 	}
2479130c231Sitojun 	return (error);
2489130c231Sitojun }
249