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