1139826Simp/*- 254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3222488Srwatson * Copyright (c) 2010-2011 Juniper Networks, Inc. 4265946Skevlo * Copyright (c) 2014 Kevin Lo 554263Sshin * All rights reserved. 654263Sshin * 7222488Srwatson * Portions of this software were developed by Robert N. M. Watson under 8222488Srwatson * contract to Juniper Networks, Inc. 9222488Srwatson * 1054263Sshin * Redistribution and use in source and binary forms, with or without 1154263Sshin * modification, are permitted provided that the following conditions 1254263Sshin * are met: 1354263Sshin * 1. Redistributions of source code must retain the above copyright 1454263Sshin * notice, this list of conditions and the following disclaimer. 1554263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1654263Sshin * notice, this list of conditions and the following disclaimer in the 1754263Sshin * documentation and/or other materials provided with the distribution. 1854263Sshin * 3. Neither the name of the project nor the names of its contributors 1954263Sshin * may be used to endorse or promote products derived from this software 2054263Sshin * without specific prior written permission. 2154263Sshin * 2254263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2354263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2454263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2554263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2654263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2754263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2854263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2954263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3054263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3154263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3254263Sshin * SUCH DAMAGE. 33174510Sobrien * 34174510Sobrien * $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ 35174510Sobrien * $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ 3654263Sshin */ 3754263Sshin 38139826Simp/*- 39172087Srwatson * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 40171328Srwatson * The Regents of the University of California. 41171328Srwatson * All rights reserved. 4254263Sshin * 4354263Sshin * Redistribution and use in source and binary forms, with or without 4454263Sshin * modification, are permitted provided that the following conditions 4554263Sshin * are met: 4654263Sshin * 1. Redistributions of source code must retain the above copyright 4754263Sshin * notice, this list of conditions and the following disclaimer. 4854263Sshin * 2. Redistributions in binary form must reproduce the above copyright 4954263Sshin * notice, this list of conditions and the following disclaimer in the 5054263Sshin * documentation and/or other materials provided with the distribution. 5154263Sshin * 4. Neither the name of the University nor the names of its contributors 5254263Sshin * may be used to endorse or promote products derived from this software 5354263Sshin * without specific prior written permission. 5454263Sshin * 5554263Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5654263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5754263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5854263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5954263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6054263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6154263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6254263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6354263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6454263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6554263Sshin * SUCH DAMAGE. 6654263Sshin * 67172087Srwatson * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 6854263Sshin */ 6954263Sshin 70174510Sobrien#include <sys/cdefs.h> 71174510Sobrien__FBSDID("$FreeBSD: stable/10/sys/netinet6/udp6_usrreq.c 338985 2018-09-27 18:48:50Z gordon $"); 72174510Sobrien 7362587Sitojun#include "opt_inet.h" 7462587Sitojun#include "opt_inet6.h" 75225044Sbz#include "opt_ipfw.h" 7655009Sshin#include "opt_ipsec.h" 77254889Smarkj#include "opt_kdtrace.h" 7855009Sshin 7954263Sshin#include <sys/param.h> 80185435Sbz#include <sys/jail.h> 8154263Sshin#include <sys/kernel.h> 8295759Stanimura#include <sys/lock.h> 8354263Sshin#include <sys/mbuf.h> 84164033Srwatson#include <sys/priv.h> 8595759Stanimura#include <sys/proc.h> 8654263Sshin#include <sys/protosw.h> 87254889Smarkj#include <sys/sdt.h> 8895759Stanimura#include <sys/signalvar.h> 8954263Sshin#include <sys/socket.h> 9054263Sshin#include <sys/socketvar.h> 9195759Stanimura#include <sys/sx.h> 9254263Sshin#include <sys/sysctl.h> 9395759Stanimura#include <sys/syslog.h> 9454263Sshin#include <sys/systm.h> 9554263Sshin 9654263Sshin#include <net/if.h> 9795759Stanimura#include <net/if_types.h> 9854263Sshin#include <net/route.h> 9954263Sshin 10054263Sshin#include <netinet/in.h> 101254889Smarkj#include <netinet/in_kdtrace.h> 10295759Stanimura#include <netinet/in_pcb.h> 10354263Sshin#include <netinet/in_systm.h> 10495759Stanimura#include <netinet/in_var.h> 10554263Sshin#include <netinet/ip.h> 106171508Srwatson#include <netinet/ip_icmp.h> 10795759Stanimura#include <netinet/ip6.h> 108171508Srwatson#include <netinet/icmp_var.h> 10995759Stanimura#include <netinet/icmp6.h> 11054263Sshin#include <netinet/ip_var.h> 11154263Sshin#include <netinet/udp.h> 11254263Sshin#include <netinet/udp_var.h> 113265946Skevlo#include <netinet/udplite.h> 114185571Sbz 11595759Stanimura#include <netinet6/ip6protosw.h> 11654263Sshin#include <netinet6/ip6_var.h> 11754263Sshin#include <netinet6/in6_pcb.h> 11854263Sshin#include <netinet6/udp6_var.h> 119148385Sume#include <netinet6/scope6_var.h> 12054263Sshin 121171167Sgnn#ifdef IPSEC 122105199Ssam#include <netipsec/ipsec.h> 123105199Ssam#include <netipsec/ipsec6.h> 124171167Sgnn#endif /* IPSEC */ 125105199Ssam 126171508Srwatson#include <security/mac/mac_framework.h> 127171508Srwatson 12854263Sshin/* 129172087Srwatson * UDP protocol implementation. 13054263Sshin * Per RFC 768, August, 1980. 13154263Sshin */ 13254263Sshin 133171328Srwatsonextern struct protosw inetsw[]; 134171328Srwatsonstatic void udp6_detach(struct socket *so); 13554263Sshin 136158237Srwatsonstatic void 137172087Srwatsonudp6_append(struct inpcb *inp, struct mbuf *n, int off, 138158237Srwatson struct sockaddr_in6 *fromsa) 139158237Srwatson{ 140158237Srwatson struct socket *so; 141158237Srwatson struct mbuf *opts; 142274265Sbryanv struct udpcb *up; 143158237Srwatson 144178419Srwatson INP_LOCK_ASSERT(inp); 145158237Srwatson 146274265Sbryanv /* 147274265Sbryanv * Engage the tunneling protocol. 148274265Sbryanv */ 149274265Sbryanv up = intoudpcb(inp); 150274265Sbryanv if (up->u_tun_func != NULL) { 151277789Sbryanv (*up->u_tun_func)(n, off, inp, (struct sockaddr *)fromsa, 152277789Sbryanv up->u_tun_ctx); 153274265Sbryanv return; 154274265Sbryanv } 155171167Sgnn#ifdef IPSEC 156171328Srwatson /* Check AH/ESP integrity. */ 157172087Srwatson if (ipsec6_in_reject(n, inp)) { 158158237Srwatson m_freem(n); 159253571Sae IPSEC6STAT_INC(ips_in_polvio); 160158237Srwatson return; 161158237Srwatson } 162171167Sgnn#endif /* IPSEC */ 163171508Srwatson#ifdef MAC 164172930Srwatson if (mac_inpcb_check_deliver(inp, n) != 0) { 165171508Srwatson m_freem(n); 166171508Srwatson return; 167171508Srwatson } 168171508Srwatson#endif 169158237Srwatson opts = NULL; 170186223Sbz if (inp->inp_flags & INP_CONTROLOPTS || 171172087Srwatson inp->inp_socket->so_options & SO_TIMESTAMP) 172172087Srwatson ip6_savecontrol(inp, n, &opts); 173158237Srwatson m_adj(n, off + sizeof(struct udphdr)); 174158237Srwatson 175172087Srwatson so = inp->inp_socket; 176158237Srwatson SOCKBUF_LOCK(&so->so_rcv); 177158237Srwatson if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n, 178158237Srwatson opts) == 0) { 179158237Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 180158237Srwatson m_freem(n); 181158237Srwatson if (opts) 182158237Srwatson m_freem(opts); 183190963Srwatson UDPSTAT_INC(udps_fullsock); 184158237Srwatson } else 185158237Srwatson sorwakeup_locked(so); 186158237Srwatson} 187158237Srwatson 18854263Sshinint 189171259Sdelphijudp6_input(struct mbuf **mp, int *offp, int proto) 19054263Sshin{ 191158237Srwatson struct mbuf *m = *mp; 192191672Sbms struct ifnet *ifp; 193171328Srwatson struct ip6_hdr *ip6; 194171328Srwatson struct udphdr *uh; 195172087Srwatson struct inpcb *inp; 196265946Skevlo struct inpcbinfo *pcbinfo; 197192649Sbz struct udpcb *up; 19854263Sshin int off = *offp; 199265946Skevlo int cscov_partial; 20054263Sshin int plen, ulen; 201121901Sume struct sockaddr_in6 fromsa; 202225044Sbz struct m_tag *fwd_tag; 203235959Sbz uint16_t uh_sum; 204265946Skevlo uint8_t nxt; 20554263Sshin 206191672Sbms ifp = m->m_pkthdr.rcvif; 20778064Sume ip6 = mtod(m, struct ip6_hdr *); 20878064Sume 20983934Sbrooks if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 21078064Sume /* XXX send icmp6 host/port unreach? */ 21178064Sume m_freem(m); 212171328Srwatson return (IPPROTO_DONE); 21354263Sshin } 21478064Sume 215125777Sume#ifndef PULLDOWN_TEST 216125777Sume IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 217125777Sume ip6 = mtod(m, struct ip6_hdr *); 218125777Sume uh = (struct udphdr *)((caddr_t)ip6 + off); 219125777Sume#else 220125777Sume IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); 221125777Sume if (!uh) 222171328Srwatson return (IPPROTO_DONE); 223125777Sume#endif 224125777Sume 225190963Srwatson UDPSTAT_INC(udps_ipackets); 22654263Sshin 227171508Srwatson /* 228171508Srwatson * Destination port of 0 is illegal, based on RFC768. 229171508Srwatson */ 230171508Srwatson if (uh->uh_dport == 0) 231171508Srwatson goto badunlocked; 232171508Srwatson 23354263Sshin plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 23454263Sshin ulen = ntohs((u_short)uh->uh_ulen); 23554263Sshin 236265946Skevlo nxt = ip6->ip6_nxt; 237265946Skevlo cscov_partial = (nxt == IPPROTO_UDPLITE) ? 1 : 0; 238272662Stuexen if (nxt == IPPROTO_UDPLITE) { 239265946Skevlo /* Zero means checksum over the complete packet. */ 240272645Stuexen if (ulen == 0) 241272645Stuexen ulen = plen; 242272662Stuexen if (ulen == plen) 243272662Stuexen cscov_partial = 0; 244272662Stuexen if ((ulen < sizeof(struct udphdr)) || (ulen > plen)) { 245272662Stuexen /* XXX: What is the right UDPLite MIB counter? */ 246272662Stuexen goto badunlocked; 247272662Stuexen } 248272664Stuexen if (uh->uh_sum == 0) { 249272664Stuexen /* XXX: What is the right UDPLite MIB counter? */ 250272664Stuexen goto badunlocked; 251272664Stuexen } 252272663Stuexen } else { 253272663Stuexen if ((ulen < sizeof(struct udphdr)) || (plen != ulen)) { 254272663Stuexen UDPSTAT_INC(udps_badlen); 255265946Skevlo goto badunlocked; 256265946Skevlo } 257272664Stuexen if (uh->uh_sum == 0) { 258272664Stuexen UDPSTAT_INC(udps_nosum); 259272664Stuexen goto badunlocked; 260272664Stuexen } 261127711Ssuz } 262235959Sbz 263265946Skevlo if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) && 264265946Skevlo !cscov_partial) { 265235959Sbz if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 266235959Sbz uh_sum = m->m_pkthdr.csum_data; 267235959Sbz else 268265946Skevlo uh_sum = in6_cksum_pseudo(ip6, ulen, nxt, 269265946Skevlo m->m_pkthdr.csum_data); 270235959Sbz uh_sum ^= 0xffff; 271235959Sbz } else 272272662Stuexen uh_sum = in6_cksum_partial(m, nxt, off, plen, ulen); 273235959Sbz 274235959Sbz if (uh_sum != 0) { 275190963Srwatson UDPSTAT_INC(udps_badsum); 276272754Stuexen goto badunlocked; 27754263Sshin } 27854263Sshin 279158237Srwatson /* 280158237Srwatson * Construct sockaddr format source address. 281158237Srwatson */ 282158237Srwatson init_sin6(&fromsa, m); 283158237Srwatson fromsa.sin6_port = uh->uh_sport; 284158237Srwatson 285265946Skevlo pcbinfo = get_inpcbinfo(nxt); 28654263Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 287171328Srwatson struct inpcb *last; 288265946Skevlo struct inpcbhead *pcblist; 289191672Sbms struct ip6_moptions *imo; 29054263Sshin 291265946Skevlo INP_INFO_RLOCK(pcbinfo); 29254263Sshin /* 293171328Srwatson * In the event that laddr should be set to the link-local 29454263Sshin * address (this happens in RIPng), the multicast address 295171328Srwatson * specified in the received packet will not match laddr. To 296171328Srwatson * handle this situation, matching is relaxed if the 297171328Srwatson * receiving interface is the same as one specified in the 298171328Srwatson * socket and if the destination multicast address matches 299171328Srwatson * one of the multicast groups specified in the socket. 30054263Sshin */ 30154263Sshin 30254263Sshin /* 303171328Srwatson * KAME note: traditionally we dropped udpiphdr from mbuf 304171328Srwatson * here. We need udphdr for IPsec processing so we do that 305171328Srwatson * later. 30654263Sshin */ 307265946Skevlo pcblist = get_pcblist(nxt); 30854263Sshin last = NULL; 309265946Skevlo LIST_FOREACH(inp, pcblist, inp_list) { 310172087Srwatson if ((inp->inp_vflag & INP_IPV6) == 0) 31154263Sshin continue; 312186141Sbz if (inp->inp_lport != uh->uh_dport) 31354263Sshin continue; 314172087Srwatson if (inp->inp_fport != 0 && 315172087Srwatson inp->inp_fport != uh->uh_sport) 316171508Srwatson continue; 317172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 318172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, 319125777Sume &ip6->ip6_dst)) 32054263Sshin continue; 32154263Sshin } 322172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 323172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, 32454263Sshin &ip6->ip6_src) || 325186141Sbz inp->inp_fport != uh->uh_sport) 32654263Sshin continue; 32754263Sshin } 32854263Sshin 329191672Sbms /* 330222488Srwatson * XXXRW: Because we weren't holding either the inpcb 331222488Srwatson * or the hash lock when we checked for a match 332222488Srwatson * before, we should probably recheck now that the 333222488Srwatson * inpcb lock is (supposed to be) held. 334222488Srwatson */ 335222488Srwatson 336222488Srwatson /* 337191672Sbms * Handle socket delivery policy for any-source 338191672Sbms * and source-specific multicast. [RFC3678] 339191672Sbms */ 340191672Sbms imo = inp->in6p_moptions; 341191672Sbms if (imo && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 342191672Sbms struct sockaddr_in6 mcaddr; 343191672Sbms int blocked; 344191672Sbms 345191718Sbms INP_RLOCK(inp); 346191718Sbms 347191672Sbms bzero(&mcaddr, sizeof(struct sockaddr_in6)); 348191672Sbms mcaddr.sin6_len = sizeof(struct sockaddr_in6); 349191672Sbms mcaddr.sin6_family = AF_INET6; 350191672Sbms mcaddr.sin6_addr = ip6->ip6_dst; 351191672Sbms 352191672Sbms blocked = im6o_mc_filter(imo, ifp, 353191672Sbms (struct sockaddr *)&mcaddr, 354191672Sbms (struct sockaddr *)&fromsa); 355191672Sbms if (blocked != MCAST_PASS) { 356191672Sbms if (blocked == MCAST_NOTGMEMBER) 357191672Sbms IP6STAT_INC(ip6s_notmember); 358191672Sbms if (blocked == MCAST_NOTSMEMBER || 359191672Sbms blocked == MCAST_MUTED) 360191672Sbms UDPSTAT_INC(udps_filtermcast); 361191718Sbms INP_RUNLOCK(inp); /* XXX */ 362191672Sbms continue; 363191672Sbms } 364191718Sbms 365191718Sbms INP_RUNLOCK(inp); 366191672Sbms } 36754263Sshin if (last != NULL) { 368125777Sume struct mbuf *n; 36954263Sshin 37054263Sshin if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 371178419Srwatson INP_RLOCK(last); 372274266Sbryanv UDP_PROBE(receive, NULL, last, ip6, 373274266Sbryanv last, uh); 374274265Sbryanv udp6_append(last, n, off, &fromsa); 375192649Sbz INP_RUNLOCK(last); 37654263Sshin } 37754263Sshin } 378172087Srwatson last = inp; 37954263Sshin /* 38054263Sshin * Don't look for additional matches if this one does 38154263Sshin * not have either the SO_REUSEPORT or SO_REUSEADDR 382171328Srwatson * socket options set. This heuristic avoids 383171328Srwatson * searching through all pcbs in the common case of a 384171328Srwatson * non-shared port. It assumes that an application 385171328Srwatson * will never clear these options after setting them. 38654263Sshin */ 387172087Srwatson if ((last->inp_socket->so_options & 38897658Stanimura (SO_REUSEPORT|SO_REUSEADDR)) == 0) 38954263Sshin break; 39054263Sshin } 39154263Sshin 39254263Sshin if (last == NULL) { 39354263Sshin /* 394171328Srwatson * No matching pcb found; discard datagram. (No need 395171328Srwatson * to send an ICMP Port Unreachable for a broadcast 396171328Srwatson * or multicast datgram.) 39754263Sshin */ 398190963Srwatson UDPSTAT_INC(udps_noport); 399190963Srwatson UDPSTAT_INC(udps_noportmcast); 400171328Srwatson goto badheadlocked; 40154263Sshin } 402178419Srwatson INP_RLOCK(last); 403265946Skevlo INP_INFO_RUNLOCK(pcbinfo); 404254889Smarkj UDP_PROBE(receive, NULL, last, ip6, last, uh); 405274265Sbryanv udp6_append(last, m, off, &fromsa); 406178419Srwatson INP_RUNLOCK(last); 407171328Srwatson return (IPPROTO_DONE); 40854263Sshin } 40954263Sshin /* 41054263Sshin * Locate pcb for datagram. 41154263Sshin */ 412242079Sae 413225044Sbz /* 414225044Sbz * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. 415225044Sbz */ 416242463Sae if ((m->m_flags & M_IP6_NEXTHOP) && 417242079Sae (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 418225044Sbz struct sockaddr_in6 *next_hop6; 419225044Sbz 420225044Sbz next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); 421225044Sbz 422225044Sbz /* 423225044Sbz * Transparently forwarded. Pretend to be the destination. 424225044Sbz * Already got one like this? 425225044Sbz */ 426265946Skevlo inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, 427265946Skevlo uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 428225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); 429225044Sbz if (!inp) { 430225044Sbz /* 431225044Sbz * It's new. Try to find the ambushing socket. 432225044Sbz * Because we've rewritten the destination address, 433225044Sbz * any hardware-generated hash is ignored. 434225044Sbz */ 435265946Skevlo inp = in6_pcblookup(pcbinfo, &ip6->ip6_src, 436225044Sbz uh->uh_sport, &next_hop6->sin6_addr, 437225044Sbz next_hop6->sin6_port ? htons(next_hop6->sin6_port) : 438225044Sbz uh->uh_dport, INPLOOKUP_WILDCARD | 439225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); 440225044Sbz } 441225044Sbz /* Remove the tag from the packet. We don't need it anymore. */ 442225044Sbz m_tag_delete(m, fwd_tag); 443242463Sae m->m_flags &= ~M_IP6_NEXTHOP; 444225044Sbz } else 445265946Skevlo inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, 446225044Sbz uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 447225044Sbz INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, 448225044Sbz m->m_pkthdr.rcvif, m); 449172087Srwatson if (inp == NULL) { 450166842Srwatson if (udp_log_in_vain) { 451165118Sbz char ip6bufs[INET6_ADDRSTRLEN]; 452165118Sbz char ip6bufd[INET6_ADDRSTRLEN]; 45354263Sshin 45454263Sshin log(LOG_INFO, 455102131Sjmallett "Connection attempt to UDP [%s]:%d from [%s]:%d\n", 456165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), 457165118Sbz ntohs(uh->uh_dport), 458165118Sbz ip6_sprintf(ip6bufs, &ip6->ip6_src), 459165118Sbz ntohs(uh->uh_sport)); 46054263Sshin } 461190963Srwatson UDPSTAT_INC(udps_noport); 46254263Sshin if (m->m_flags & M_MCAST) { 46354263Sshin printf("UDP6: M_MCAST is set in a unicast packet.\n"); 464190963Srwatson UDPSTAT_INC(udps_noportmcast); 465222488Srwatson goto badunlocked; 46654263Sshin } 467181803Sbz if (V_udp_blackhole) 468171508Srwatson goto badunlocked; 469171508Srwatson if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0) 470171508Srwatson goto badunlocked; 47154263Sshin icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 472171328Srwatson return (IPPROTO_DONE); 47354263Sshin } 474222488Srwatson INP_RLOCK_ASSERT(inp); 475192649Sbz up = intoudpcb(inp); 476265946Skevlo if (cscov_partial) { 477272661Stuexen if (up->u_rxcslen == 0 || up->u_rxcslen > ulen) { 478265946Skevlo INP_RUNLOCK(inp); 479265946Skevlo m_freem(m); 480265946Skevlo return (IPPROTO_DONE); 481265946Skevlo } 482265946Skevlo } 483254889Smarkj UDP_PROBE(receive, NULL, inp, ip6, inp, uh); 484274265Sbryanv udp6_append(inp, m, off, &fromsa); 485178419Srwatson INP_RUNLOCK(inp); 486171328Srwatson return (IPPROTO_DONE); 487171508Srwatson 488171328Srwatsonbadheadlocked: 489265946Skevlo INP_INFO_RUNLOCK(pcbinfo); 490171328Srwatsonbadunlocked: 49154263Sshin if (m) 49254263Sshin m_freem(m); 493171328Srwatson return (IPPROTO_DONE); 49454263Sshin} 49554263Sshin 496265946Skevlostatic void 497265946Skevloudp6_common_ctlinput(int cmd, struct sockaddr *sa, void *d, 498265946Skevlo struct inpcbinfo *pcbinfo) 49954263Sshin{ 50054263Sshin struct udphdr uh; 50154263Sshin struct ip6_hdr *ip6; 50254263Sshin struct mbuf *m; 50362587Sitojun int off = 0; 50478064Sume struct ip6ctlparam *ip6cp = NULL; 50578064Sume const struct sockaddr_in6 *sa6_src = NULL; 506125776Sume void *cmdarg; 507175162Sobrien struct inpcb *(*notify)(struct inpcb *, int) = udp_notify; 50878064Sume struct udp_portonly { 50978064Sume u_int16_t uh_sport; 51078064Sume u_int16_t uh_dport; 51178064Sume } *uhp; 51254263Sshin 51354263Sshin if (sa->sa_family != AF_INET6 || 51454263Sshin sa->sa_len != sizeof(struct sockaddr_in6)) 51554263Sshin return; 51654263Sshin 51762587Sitojun if ((unsigned)cmd >= PRC_NCMDS) 51854263Sshin return; 51962587Sitojun if (PRC_IS_REDIRECT(cmd)) 52062587Sitojun notify = in6_rtchange, d = NULL; 52162587Sitojun else if (cmd == PRC_HOSTDEAD) 52262587Sitojun d = NULL; 52362587Sitojun else if (inet6ctlerrmap[cmd] == 0) 52462587Sitojun return; 52554263Sshin 52654263Sshin /* if the parameter is from icmp6, decode it. */ 52754263Sshin if (d != NULL) { 52878064Sume ip6cp = (struct ip6ctlparam *)d; 52954263Sshin m = ip6cp->ip6c_m; 53054263Sshin ip6 = ip6cp->ip6c_ip6; 53154263Sshin off = ip6cp->ip6c_off; 532125776Sume cmdarg = ip6cp->ip6c_cmdarg; 53378064Sume sa6_src = ip6cp->ip6c_src; 53454263Sshin } else { 53554263Sshin m = NULL; 53654263Sshin ip6 = NULL; 537125776Sume cmdarg = NULL; 53878064Sume sa6_src = &sa6_any; 53954263Sshin } 54054263Sshin 54154263Sshin if (ip6) { 54254263Sshin /* 54354263Sshin * XXX: We assume that when IPV6 is non NULL, 54454263Sshin * M and OFF are valid. 54554263Sshin */ 54654263Sshin 547171328Srwatson /* Check if we can safely examine src and dst ports. */ 54878064Sume if (m->m_pkthdr.len < off + sizeof(*uhp)) 54967456Sitojun return; 55067456Sitojun 55178064Sume bzero(&uh, sizeof(uh)); 55278064Sume m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 55378064Sume 554265946Skevlo (void)in6_pcbnotify(pcbinfo, sa, uh.uh_dport, 555171328Srwatson (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd, 556171328Srwatson cmdarg, notify); 55754263Sshin } else 558265946Skevlo (void)in6_pcbnotify(pcbinfo, sa, 0, 559171328Srwatson (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify); 56054263Sshin} 56154263Sshin 562265946Skevlovoid 563265946Skevloudp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 564265946Skevlo{ 565265946Skevlo 566265946Skevlo return (udp6_common_ctlinput(cmd, sa, d, &V_udbinfo)); 567265946Skevlo} 568265946Skevlo 569265946Skevlovoid 570265946Skevloudplite6_ctlinput(int cmd, struct sockaddr *sa, void *d) 571265946Skevlo{ 572265946Skevlo 573265946Skevlo return (udp6_common_ctlinput(cmd, sa, d, &V_ulitecbinfo)); 574265946Skevlo} 575265946Skevlo 57654263Sshinstatic int 57762573Sphkudp6_getcred(SYSCTL_HANDLER_ARGS) 57854263Sshin{ 57972650Sgreen struct xucred xuc; 58054263Sshin struct sockaddr_in6 addrs[2]; 58154263Sshin struct inpcb *inp; 582157674Srwatson int error; 58354263Sshin 584170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 58554263Sshin if (error) 58654263Sshin return (error); 58762587Sitojun 58862587Sitojun if (req->newlen != sizeof(addrs)) 58962587Sitojun return (EINVAL); 59072650Sgreen if (req->oldlen != sizeof(struct xucred)) 59162587Sitojun return (EINVAL); 59254263Sshin error = SYSCTL_IN(req, addrs, sizeof(addrs)); 59354263Sshin if (error) 59454263Sshin return (error); 595181803Sbz if ((error = sa6_embedscope(&addrs[0], V_ip6_use_defzone)) != 0 || 596181803Sbz (error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) { 597148385Sume return (error); 598148385Sume } 599222488Srwatson inp = in6_pcblookup(&V_udbinfo, &addrs[1].sin6_addr, 600222488Srwatson addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 601222488Srwatson INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); 602179412Srwatson if (inp != NULL) { 603222488Srwatson INP_RLOCK_ASSERT(inp); 604179412Srwatson if (inp->inp_socket == NULL) 605179412Srwatson error = ENOENT; 606179412Srwatson if (error == 0) 607179412Srwatson error = cr_canseesocket(req->td->td_ucred, 608179412Srwatson inp->inp_socket); 609179412Srwatson if (error == 0) 610183606Sbz cru2x(inp->inp_cred, &xuc); 611179412Srwatson INP_RUNLOCK(inp); 612222488Srwatson } else 613171609Srwatson error = ENOENT; 614171609Srwatson if (error == 0) 615171609Srwatson error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 61654263Sshin return (error); 61754263Sshin} 61854263Sshin 619171328SrwatsonSYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 620171328Srwatson 0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); 62154263Sshin 622171552Srwatsonstatic int 623172087Srwatsonudp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, 624171552Srwatson struct mbuf *control, struct thread *td) 625171552Srwatson{ 626171552Srwatson u_int32_t ulen = m->m_pkthdr.len; 627171552Srwatson u_int32_t plen = sizeof(struct udphdr) + ulen; 628171552Srwatson struct ip6_hdr *ip6; 629171552Srwatson struct udphdr *udp6; 630194777Sbz struct in6_addr *laddr, *faddr, in6a; 631171552Srwatson struct sockaddr_in6 *sin6 = NULL; 632171552Srwatson struct ifnet *oifp = NULL; 633265946Skevlo int cscov_partial = 0; 634171552Srwatson int scope_ambiguous = 0; 635171552Srwatson u_short fport; 636171552Srwatson int error = 0; 637265946Skevlo uint8_t nxt; 638265946Skevlo uint16_t cscov = 0; 639171552Srwatson struct ip6_pktopts *optp, opt; 640171552Srwatson int af = AF_INET6, hlen = sizeof(struct ip6_hdr); 641171552Srwatson int flags; 642171552Srwatson struct sockaddr_in6 tmp; 643171552Srwatson 644178285Srwatson INP_WLOCK_ASSERT(inp); 645222488Srwatson INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); 646171552Srwatson 647171552Srwatson if (addr6) { 648171552Srwatson /* addr6 has been validated in udp6_send(). */ 649171552Srwatson sin6 = (struct sockaddr_in6 *)addr6; 650171552Srwatson 651171552Srwatson /* protect *sin6 from overwrites */ 652171552Srwatson tmp = *sin6; 653171552Srwatson sin6 = &tmp; 654171552Srwatson 655171552Srwatson /* 656171552Srwatson * Application should provide a proper zone ID or the use of 657171552Srwatson * default zone IDs should be enabled. Unfortunately, some 658171552Srwatson * applications do not behave as it should, so we need a 659171552Srwatson * workaround. Even if an appropriate ID is not determined, 660171552Srwatson * we'll see if we can determine the outgoing interface. If we 661171552Srwatson * can, determine the zone ID based on the interface below. 662171552Srwatson */ 663181803Sbz if (sin6->sin6_scope_id == 0 && !V_ip6_use_defzone) 664171552Srwatson scope_ambiguous = 1; 665181803Sbz if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) 666171552Srwatson return (error); 667171552Srwatson } 668171552Srwatson 669171552Srwatson if (control) { 670171552Srwatson if ((error = ip6_setpktopts(control, &opt, 671175630Sbz inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0) 672171552Srwatson goto release; 673171552Srwatson optp = &opt; 674171552Srwatson } else 675172087Srwatson optp = inp->in6p_outputopts; 676171552Srwatson 677171552Srwatson if (sin6) { 678171552Srwatson faddr = &sin6->sin6_addr; 679171552Srwatson 680171552Srwatson /* 681171552Srwatson * Since we saw no essential reason for calling in_pcbconnect, 682171552Srwatson * we get rid of such kind of logic, and call in6_selectsrc 683171552Srwatson * and in6_pcbsetport in order to fill in the local address 684171552Srwatson * and the local port. 685171552Srwatson */ 686171552Srwatson if (sin6->sin6_port == 0) { 687171552Srwatson error = EADDRNOTAVAIL; 688171552Srwatson goto release; 689171552Srwatson } 690171552Srwatson 691172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 692171552Srwatson /* how about ::ffff:0.0.0.0 case? */ 693171552Srwatson error = EISCONN; 694171552Srwatson goto release; 695171552Srwatson } 696171552Srwatson 697171552Srwatson fport = sin6->sin6_port; /* allow 0 port */ 698171552Srwatson 699171552Srwatson if (IN6_IS_ADDR_V4MAPPED(faddr)) { 700186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 701171552Srwatson /* 702171552Srwatson * I believe we should explicitly discard the 703171552Srwatson * packet when mapped addresses are disabled, 704171552Srwatson * rather than send the packet as an IPv6 one. 705171552Srwatson * If we chose the latter approach, the packet 706171552Srwatson * might be sent out on the wire based on the 707171552Srwatson * default route, the situation which we'd 708171552Srwatson * probably want to avoid. 709171552Srwatson * (20010421 jinmei@kame.net) 710171552Srwatson */ 711171552Srwatson error = EINVAL; 712171552Srwatson goto release; 713171552Srwatson } 714172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && 715172087Srwatson !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) { 716171552Srwatson /* 717171552Srwatson * when remote addr is an IPv4-mapped address, 718171552Srwatson * local addr should not be an IPv6 address, 719171552Srwatson * since you cannot determine how to map IPv6 720171552Srwatson * source address to IPv4. 721171552Srwatson */ 722171552Srwatson error = EINVAL; 723171552Srwatson goto release; 724171552Srwatson } 725171552Srwatson 726171552Srwatson af = AF_INET; 727171552Srwatson } 728171552Srwatson 729171552Srwatson if (!IN6_IS_ADDR_V4MAPPED(faddr)) { 730194777Sbz error = in6_selectsrc(sin6, optp, inp, NULL, 731194777Sbz td->td_ucred, &oifp, &in6a); 732194777Sbz if (error) 733194777Sbz goto release; 734171552Srwatson if (oifp && scope_ambiguous && 735171552Srwatson (error = in6_setscope(&sin6->sin6_addr, 736171552Srwatson oifp, NULL))) { 737171552Srwatson goto release; 738171552Srwatson } 739194777Sbz laddr = &in6a; 740171552Srwatson } else 741172087Srwatson laddr = &inp->in6p_laddr; /* XXX */ 742171552Srwatson if (laddr == NULL) { 743171552Srwatson if (error == 0) 744171552Srwatson error = EADDRNOTAVAIL; 745171552Srwatson goto release; 746171552Srwatson } 747186141Sbz if (inp->inp_lport == 0 && 748219570Sbz (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) { 749219570Sbz /* Undo an address bind that may have occurred. */ 750219570Sbz inp->in6p_laddr = in6addr_any; 751171552Srwatson goto release; 752219570Sbz } 753171552Srwatson } else { 754172087Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 755171552Srwatson error = ENOTCONN; 756171552Srwatson goto release; 757171552Srwatson } 758172087Srwatson if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { 759186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 760171552Srwatson /* 761171552Srwatson * XXX: this case would happen when the 762171552Srwatson * application sets the V6ONLY flag after 763171552Srwatson * connecting the foreign address. 764171552Srwatson * Such applications should be fixed, 765171552Srwatson * so we bark here. 766171552Srwatson */ 767171552Srwatson log(LOG_INFO, "udp6_output: IPV6_V6ONLY " 768171552Srwatson "option was set for a connected socket\n"); 769171552Srwatson error = EINVAL; 770171552Srwatson goto release; 771171552Srwatson } else 772171552Srwatson af = AF_INET; 773171552Srwatson } 774172087Srwatson laddr = &inp->in6p_laddr; 775172087Srwatson faddr = &inp->in6p_faddr; 776186141Sbz fport = inp->inp_fport; 777171552Srwatson } 778171552Srwatson 779171552Srwatson if (af == AF_INET) 780171552Srwatson hlen = sizeof(struct ip); 781171552Srwatson 782171552Srwatson /* 783171552Srwatson * Calculate data length and get a mbuf 784171552Srwatson * for UDP and IP6 headers. 785171552Srwatson */ 786243882Sglebius M_PREPEND(m, hlen + sizeof(struct udphdr), M_NOWAIT); 787171552Srwatson if (m == 0) { 788171552Srwatson error = ENOBUFS; 789171552Srwatson goto release; 790171552Srwatson } 791171552Srwatson 792171552Srwatson /* 793171552Srwatson * Stuff checksum and output datagram. 794171552Srwatson */ 795265946Skevlo nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ? 796265946Skevlo IPPROTO_UDP : IPPROTO_UDPLITE; 797171552Srwatson udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); 798186141Sbz udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ 799171552Srwatson udp6->uh_dport = fport; 800265946Skevlo if (nxt == IPPROTO_UDPLITE) { 801265946Skevlo struct udpcb *up; 802265946Skevlo 803265946Skevlo up = intoudpcb(inp); 804265946Skevlo cscov = up->u_txcslen; 805265946Skevlo if (cscov >= plen) 806265946Skevlo cscov = 0; 807265946Skevlo udp6->uh_ulen = htons(cscov); 808265946Skevlo /* 809265946Skevlo * For UDP-Lite, checksum coverage length of zero means 810265946Skevlo * the entire UDPLite packet is covered by the checksum. 811265946Skevlo */ 812265946Skevlo cscov_partial = (cscov == 0) ? 0 : 1; 813265946Skevlo } else if (plen <= 0xffff) 814171552Srwatson udp6->uh_ulen = htons((u_short)plen); 815171552Srwatson else 816171552Srwatson udp6->uh_ulen = 0; 817171552Srwatson udp6->uh_sum = 0; 818171552Srwatson 819171552Srwatson switch (af) { 820171552Srwatson case AF_INET6: 821171552Srwatson ip6 = mtod(m, struct ip6_hdr *); 822186141Sbz ip6->ip6_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; 823171552Srwatson ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 824171552Srwatson ip6->ip6_vfc |= IPV6_VERSION; 825171552Srwatson ip6->ip6_plen = htons((u_short)plen); 826265946Skevlo ip6->ip6_nxt = nxt; 827172087Srwatson ip6->ip6_hlim = in6_selecthlim(inp, NULL); 828171552Srwatson ip6->ip6_src = *laddr; 829171552Srwatson ip6->ip6_dst = *faddr; 830171552Srwatson 831265946Skevlo if (cscov_partial) { 832272662Stuexen if ((udp6->uh_sum = in6_cksum_partial(m, nxt, 833272662Stuexen sizeof(struct ip6_hdr), plen, cscov)) == 0) 834265946Skevlo udp6->uh_sum = 0xffff; 835265946Skevlo } else { 836265946Skevlo udp6->uh_sum = in6_cksum_pseudo(ip6, plen, nxt, 0); 837265946Skevlo m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; 838265946Skevlo m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); 839265946Skevlo } 840171552Srwatson 841171552Srwatson flags = 0; 842171552Srwatson 843254889Smarkj UDP_PROBE(send, NULL, inp, ip6, inp, udp6); 844190963Srwatson UDPSTAT_INC(udps_opackets); 845172087Srwatson error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions, 846172087Srwatson NULL, inp); 847171552Srwatson break; 848171552Srwatson case AF_INET: 849171552Srwatson error = EAFNOSUPPORT; 850171552Srwatson goto release; 851171552Srwatson } 852171552Srwatson goto releaseopt; 853171552Srwatson 854171552Srwatsonrelease: 855171552Srwatson m_freem(m); 856171552Srwatson 857171552Srwatsonreleaseopt: 858171552Srwatson if (control) { 859171552Srwatson ip6_clearpktopts(&opt, -1); 860171552Srwatson m_freem(control); 861171552Srwatson } 862171552Srwatson return (error); 863171552Srwatson} 864171552Srwatson 865157366Srwatsonstatic void 86654263Sshinudp6_abort(struct socket *so) 86754263Sshin{ 86854263Sshin struct inpcb *inp; 869265946Skevlo struct inpcbinfo *pcbinfo; 87054263Sshin 871265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 872157374Srwatson inp = sotoinpcb(so); 873157374Srwatson KASSERT(inp != NULL, ("udp6_abort: inp == NULL")); 874157674Srwatson 875160549Srwatson#ifdef INET 876160549Srwatson if (inp->inp_vflag & INP_IPV4) { 877160549Srwatson struct pr_usrreqs *pru; 878160549Srwatson 879160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 880160549Srwatson (*pru->pru_abort)(so); 881160549Srwatson return; 882160549Srwatson } 883160549Srwatson#endif 884160549Srwatson 885178285Srwatson INP_WLOCK(inp); 886160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 887265946Skevlo INP_HASH_WLOCK(pcbinfo); 888160549Srwatson in6_pcbdisconnect(inp); 889160549Srwatson inp->in6p_laddr = in6addr_any; 890265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 891160549Srwatson soisdisconnected(so); 892160549Srwatson } 893178285Srwatson INP_WUNLOCK(inp); 89454263Sshin} 89554263Sshin 89654263Sshinstatic int 89783366Sjulianudp6_attach(struct socket *so, int proto, struct thread *td) 89854263Sshin{ 89954263Sshin struct inpcb *inp; 900265946Skevlo struct inpcbinfo *pcbinfo; 901157674Srwatson int error; 90254263Sshin 903265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 90454263Sshin inp = sotoinpcb(so); 905157607Srwatson KASSERT(inp == NULL, ("udp6_attach: inp != NULL")); 906157674Srwatson 90754263Sshin if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 90854263Sshin error = soreserve(so, udp_sendspace, udp_recvspace); 909157374Srwatson if (error) 910171328Srwatson return (error); 91154263Sshin } 912265946Skevlo INP_INFO_WLOCK(pcbinfo); 913265946Skevlo error = in_pcballoc(so, pcbinfo); 914132714Srwatson if (error) { 915265946Skevlo INP_INFO_WUNLOCK(pcbinfo); 916171328Srwatson return (error); 917132714Srwatson } 91854263Sshin inp = (struct inpcb *)so->so_pcb; 91954263Sshin inp->inp_vflag |= INP_IPV6; 920155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) 921100132Sume inp->inp_vflag |= INP_IPV4; 92254263Sshin inp->in6p_hops = -1; /* use kernel default */ 92354263Sshin inp->in6p_cksum = -1; /* just to be sure */ 92461958Sitojun /* 92561958Sitojun * XXX: ugly!! 92661958Sitojun * IPv4 TTL initialization is necessary for an IPv6 socket as well, 92761958Sitojun * because the socket may be bound to an IPv6 wildcard address, 92861958Sitojun * which may match an IPv4-mapped IPv6 address. 92961958Sitojun */ 930181803Sbz inp->inp_ip_ttl = V_ip_defttl; 931192649Sbz 932192649Sbz error = udp_newudpcb(inp); 933192649Sbz if (error) { 934192649Sbz in_pcbdetach(inp); 935192649Sbz in_pcbfree(inp); 936265946Skevlo INP_INFO_WUNLOCK(pcbinfo); 937192649Sbz return (error); 938192649Sbz } 939178285Srwatson INP_WUNLOCK(inp); 940265946Skevlo INP_INFO_WUNLOCK(pcbinfo); 941171328Srwatson return (0); 94254263Sshin} 94354263Sshin 94454263Sshinstatic int 94583366Sjulianudp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 94654263Sshin{ 94754263Sshin struct inpcb *inp; 948265946Skevlo struct inpcbinfo *pcbinfo; 949157674Srwatson int error; 950338985Sgordon u_char vflagsav; 95154263Sshin 952265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 953157374Srwatson inp = sotoinpcb(so); 954157374Srwatson KASSERT(inp != NULL, ("udp6_bind: inp == NULL")); 955157674Srwatson 956178285Srwatson INP_WLOCK(inp); 957265946Skevlo INP_HASH_WLOCK(pcbinfo); 958338985Sgordon vflagsav = inp->inp_vflag; 95954263Sshin inp->inp_vflag &= ~INP_IPV4; 96054263Sshin inp->inp_vflag |= INP_IPV6; 96178064Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 96254263Sshin struct sockaddr_in6 *sin6_p; 96354263Sshin 96454263Sshin sin6_p = (struct sockaddr_in6 *)nam; 96554263Sshin 96654263Sshin if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 96754263Sshin inp->inp_vflag |= INP_IPV4; 968221248Sbz#ifdef INET 96954263Sshin else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 97054263Sshin struct sockaddr_in sin; 97154263Sshin 97254263Sshin in6_sin6_2_sin(&sin, sin6_p); 97354263Sshin inp->inp_vflag |= INP_IPV4; 97454263Sshin inp->inp_vflag &= ~INP_IPV6; 975127505Spjd error = in_pcbbind(inp, (struct sockaddr *)&sin, 976127505Spjd td->td_ucred); 977132714Srwatson goto out; 97854263Sshin } 979221248Sbz#endif 98054263Sshin } 98154263Sshin 982127505Spjd error = in6_pcbbind(inp, nam, td->td_ucred); 983221248Sbz#ifdef INET 984132714Srwatsonout: 985221248Sbz#endif 986338985Sgordon if (error != 0) 987338985Sgordon inp->inp_vflag = vflagsav; 988265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 989178285Srwatson INP_WUNLOCK(inp); 990171328Srwatson return (error); 99154263Sshin} 99254263Sshin 993160549Srwatsonstatic void 994160549Srwatsonudp6_close(struct socket *so) 995160549Srwatson{ 996160549Srwatson struct inpcb *inp; 997265946Skevlo struct inpcbinfo *pcbinfo; 998160549Srwatson 999265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 1000160549Srwatson inp = sotoinpcb(so); 1001160549Srwatson KASSERT(inp != NULL, ("udp6_close: inp == NULL")); 1002160549Srwatson 1003160549Srwatson#ifdef INET 1004160549Srwatson if (inp->inp_vflag & INP_IPV4) { 1005160549Srwatson struct pr_usrreqs *pru; 1006160549Srwatson 1007160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1008160549Srwatson (*pru->pru_disconnect)(so); 1009160549Srwatson return; 1010160549Srwatson } 1011160549Srwatson#endif 1012178285Srwatson INP_WLOCK(inp); 1013160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1014265946Skevlo INP_HASH_WLOCK(pcbinfo); 1015160549Srwatson in6_pcbdisconnect(inp); 1016160549Srwatson inp->in6p_laddr = in6addr_any; 1017265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 1018160549Srwatson soisdisconnected(so); 1019160549Srwatson } 1020178285Srwatson INP_WUNLOCK(inp); 1021160549Srwatson} 1022160549Srwatson 102354263Sshinstatic int 102483366Sjulianudp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 102554263Sshin{ 102654263Sshin struct inpcb *inp; 1027265946Skevlo struct inpcbinfo *pcbinfo; 1028188151Sjamie struct sockaddr_in6 *sin6; 1029157674Srwatson int error; 1030338985Sgordon u_char vflagsav; 103154263Sshin 1032265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 1033157374Srwatson inp = sotoinpcb(so); 1034188151Sjamie sin6 = (struct sockaddr_in6 *)nam; 1035157374Srwatson KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); 1036157674Srwatson 1037222488Srwatson /* 1038222488Srwatson * XXXRW: Need to clarify locking of v4/v6 flags. 1039222488Srwatson */ 1040178285Srwatson INP_WLOCK(inp); 1041221248Sbz#ifdef INET 1042220462Sbz if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1043188151Sjamie struct sockaddr_in sin; 104454263Sshin 1045220462Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { 1046220462Sbz error = EINVAL; 1047220462Sbz goto out; 1048220462Sbz } 1049188151Sjamie if (inp->inp_faddr.s_addr != INADDR_ANY) { 1050188151Sjamie error = EISCONN; 1051132714Srwatson goto out; 105254263Sshin } 1053188151Sjamie in6_sin6_2_sin(&sin, sin6); 1054188151Sjamie error = prison_remote_ip4(td->td_ucred, &sin.sin_addr); 1055188151Sjamie if (error != 0) 1056188151Sjamie goto out; 1057338985Sgordon vflagsav = inp->inp_vflag; 1058338985Sgordon inp->inp_vflag |= INP_IPV4; 1059338985Sgordon inp->inp_vflag &= ~INP_IPV6; 1060265946Skevlo INP_HASH_WLOCK(pcbinfo); 1061188151Sjamie error = in_pcbconnect(inp, (struct sockaddr *)&sin, 1062188151Sjamie td->td_ucred); 1063265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 1064338985Sgordon /* 1065338985Sgordon * If connect succeeds, mark socket as connected. If 1066338985Sgordon * connect fails and socket is unbound, reset inp_vflag 1067338985Sgordon * field. 1068338985Sgordon */ 1069220462Sbz if (error == 0) 1070188151Sjamie soisconnected(so); 1071338985Sgordon else if (inp->inp_laddr.s_addr == INADDR_ANY && 1072338985Sgordon inp->inp_lport == 0) 1073338985Sgordon inp->inp_vflag = vflagsav; 1074188151Sjamie goto out; 107554263Sshin } 1076221248Sbz#endif 1077132714Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1078132714Srwatson error = EISCONN; 1079132714Srwatson goto out; 1080132714Srwatson } 1081188151Sjamie error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); 1082188151Sjamie if (error != 0) 1083188151Sjamie goto out; 1084338985Sgordon vflagsav = inp->inp_vflag; 1085338985Sgordon inp->inp_vflag &= ~INP_IPV4; 1086338985Sgordon inp->inp_vflag |= INP_IPV6; 1087265946Skevlo INP_HASH_WLOCK(pcbinfo); 1088127505Spjd error = in6_pcbconnect(inp, nam, td->td_ucred); 1089265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 1090338985Sgordon /* 1091338985Sgordon * If connect succeeds, mark socket as connected. If 1092338985Sgordon * connect fails and socket is unbound, reset inp_vflag 1093338985Sgordon * field. 1094338985Sgordon */ 1095220462Sbz if (error == 0) 109654263Sshin soisconnected(so); 1097338985Sgordon else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && 1098338985Sgordon inp->inp_lport == 0) 1099338985Sgordon inp->inp_vflag = vflagsav; 1100132714Srwatsonout: 1101178285Srwatson INP_WUNLOCK(inp); 1102171328Srwatson return (error); 110354263Sshin} 110454263Sshin 1105157370Srwatsonstatic void 110654263Sshinudp6_detach(struct socket *so) 110754263Sshin{ 110854263Sshin struct inpcb *inp; 1109265946Skevlo struct inpcbinfo *pcbinfo; 1110192649Sbz struct udpcb *up; 111154263Sshin 1112265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 1113157374Srwatson inp = sotoinpcb(so); 1114157374Srwatson KASSERT(inp != NULL, ("udp6_detach: inp == NULL")); 1115157674Srwatson 1116265946Skevlo INP_INFO_WLOCK(pcbinfo); 1117178285Srwatson INP_WLOCK(inp); 1118192649Sbz up = intoudpcb(inp); 1119192649Sbz KASSERT(up != NULL, ("%s: up == NULL", __func__)); 1120185344Sbz in_pcbdetach(inp); 1121185370Sbz in_pcbfree(inp); 1122265946Skevlo INP_INFO_WUNLOCK(pcbinfo); 1123192649Sbz udp_discardcb(up); 112454263Sshin} 112554263Sshin 112654263Sshinstatic int 112754263Sshinudp6_disconnect(struct socket *so) 112854263Sshin{ 112954263Sshin struct inpcb *inp; 1130265946Skevlo struct inpcbinfo *pcbinfo; 1131157674Srwatson int error; 113254263Sshin 1133265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 1134157374Srwatson inp = sotoinpcb(so); 1135157374Srwatson KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL")); 1136157674Srwatson 1137125777Sume#ifdef INET 113854263Sshin if (inp->inp_vflag & INP_IPV4) { 113954263Sshin struct pr_usrreqs *pru; 114054263Sshin 114154263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1142222488Srwatson (void)(*pru->pru_disconnect)(so); 1143222488Srwatson return (0); 114454263Sshin } 1145125777Sume#endif 114654263Sshin 1147222488Srwatson INP_WLOCK(inp); 1148222488Srwatson 1149132714Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1150132714Srwatson error = ENOTCONN; 1151132714Srwatson goto out; 1152132714Srwatson } 115354263Sshin 1154265946Skevlo INP_HASH_WLOCK(pcbinfo); 115554263Sshin in6_pcbdisconnect(inp); 115654263Sshin inp->in6p_laddr = in6addr_any; 1157265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 1158183807Srwatson SOCK_LOCK(so); 115954263Sshin so->so_state &= ~SS_ISCONNECTED; /* XXX */ 1160183807Srwatson SOCK_UNLOCK(so); 1161132714Srwatsonout: 1162178285Srwatson INP_WUNLOCK(inp); 1163171328Srwatson return (0); 116454263Sshin} 116554263Sshin 116654263Sshinstatic int 1167171328Srwatsonudp6_send(struct socket *so, int flags, struct mbuf *m, 1168171328Srwatson struct sockaddr *addr, struct mbuf *control, struct thread *td) 116954263Sshin{ 117054263Sshin struct inpcb *inp; 1171265946Skevlo struct inpcbinfo *pcbinfo; 117262587Sitojun int error = 0; 117354263Sshin 1174265946Skevlo pcbinfo = get_inpcbinfo(so->so_proto->pr_protocol); 1175157374Srwatson inp = sotoinpcb(so); 1176157374Srwatson KASSERT(inp != NULL, ("udp6_send: inp == NULL")); 1177157674Srwatson 1178178285Srwatson INP_WLOCK(inp); 117962587Sitojun if (addr) { 1180171260Sdelphij if (addr->sa_len != sizeof(struct sockaddr_in6)) { 118162587Sitojun error = EINVAL; 118262587Sitojun goto bad; 118362587Sitojun } 118462587Sitojun if (addr->sa_family != AF_INET6) { 118562587Sitojun error = EAFNOSUPPORT; 118662587Sitojun goto bad; 118762587Sitojun } 118862587Sitojun } 118962587Sitojun 1190125777Sume#ifdef INET 1191155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 119254263Sshin int hasv4addr; 119354263Sshin struct sockaddr_in6 *sin6 = 0; 119454263Sshin 119554263Sshin if (addr == 0) 119654263Sshin hasv4addr = (inp->inp_vflag & INP_IPV4); 119754263Sshin else { 119854263Sshin sin6 = (struct sockaddr_in6 *)addr; 119954263Sshin hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) 1200171328Srwatson ? 1 : 0; 120154263Sshin } 120254263Sshin if (hasv4addr) { 120354263Sshin struct pr_usrreqs *pru; 120454263Sshin 1205183265Srwatson /* 1206183265Srwatson * XXXRW: We release UDP-layer locks before calling 1207183265Srwatson * udp_send() in order to avoid recursion. However, 1208183265Srwatson * this does mean there is a short window where inp's 1209183265Srwatson * fields are unstable. Could this lead to a 1210183265Srwatson * potential race in which the factors causing us to 1211183265Srwatson * select the UDPv4 output routine are invalidated? 1212183265Srwatson */ 1213183265Srwatson INP_WUNLOCK(inp); 121454263Sshin if (sin6) 121554263Sshin in6_sin6_2_sin_in_sock(addr); 121654263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1217183265Srwatson /* addr will just be freed in sendit(). */ 1218183265Srwatson return ((*pru->pru_send)(so, flags, m, addr, control, 1219171328Srwatson td)); 122054263Sshin } 122154263Sshin } 1222125777Sume#endif 1223171508Srwatson#ifdef MAC 1224172930Srwatson mac_inpcb_create_mbuf(inp, m); 1225171508Srwatson#endif 1226265946Skevlo INP_HASH_WLOCK(pcbinfo); 1227132714Srwatson error = udp6_output(inp, m, addr, control, td); 1228265946Skevlo INP_HASH_WUNLOCK(pcbinfo); 1229207828Skmacy#ifdef INET 1230207828Skmacy#endif 1231178285Srwatson INP_WUNLOCK(inp); 1232171328Srwatson return (error); 123362587Sitojun 1234171328Srwatsonbad: 1235178285Srwatson INP_WUNLOCK(inp); 123662587Sitojun m_freem(m); 1237120856Sume return (error); 123854263Sshin} 123954263Sshin 124054263Sshinstruct pr_usrreqs udp6_usrreqs = { 1241137386Sphk .pru_abort = udp6_abort, 1242137386Sphk .pru_attach = udp6_attach, 1243137386Sphk .pru_bind = udp6_bind, 1244137386Sphk .pru_connect = udp6_connect, 1245137386Sphk .pru_control = in6_control, 1246137386Sphk .pru_detach = udp6_detach, 1247137386Sphk .pru_disconnect = udp6_disconnect, 1248137386Sphk .pru_peeraddr = in6_mapped_peeraddr, 1249137386Sphk .pru_send = udp6_send, 1250137386Sphk .pru_shutdown = udp_shutdown, 1251137386Sphk .pru_sockaddr = in6_mapped_sockaddr, 1252180365Srwatson .pru_soreceive = soreceive_dgram, 1253180365Srwatson .pru_sosend = sosend_dgram, 1254160549Srwatson .pru_sosetlabel = in_pcbsosetlabel, 1255160549Srwatson .pru_close = udp6_close 125654263Sshin}; 1257