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