1139826Simp/*- 254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3222488Srwatson * Copyright (c) 2010-2011 Juniper Networks, Inc. 454263Sshin * All rights reserved. 554263Sshin * 6222488Srwatson * Portions of this software were developed by Robert N. M. Watson under 7222488Srwatson * contract to Juniper Networks, Inc. 8222488Srwatson * 954263Sshin * Redistribution and use in source and binary forms, with or without 1054263Sshin * modification, are permitted provided that the following conditions 1154263Sshin * are met: 1254263Sshin * 1. Redistributions of source code must retain the above copyright 1354263Sshin * notice, this list of conditions and the following disclaimer. 1454263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1554263Sshin * notice, this list of conditions and the following disclaimer in the 1654263Sshin * documentation and/or other materials provided with the distribution. 1754263Sshin * 3. Neither the name of the project nor the names of its contributors 1854263Sshin * may be used to endorse or promote products derived from this software 1954263Sshin * without specific prior written permission. 2054263Sshin * 2154263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2254263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2354263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2454263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2554263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2654263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2754263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2854263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2954263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3054263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3154263Sshin * SUCH DAMAGE. 32174510Sobrien * 33174510Sobrien * $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ 34174510Sobrien * $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ 3554263Sshin */ 3654263Sshin 37139826Simp/*- 38172087Srwatson * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 39171328Srwatson * The Regents of the University of California. 40171328Srwatson * All rights reserved. 4154263Sshin * 4254263Sshin * Redistribution and use in source and binary forms, with or without 4354263Sshin * modification, are permitted provided that the following conditions 4454263Sshin * are met: 4554263Sshin * 1. Redistributions of source code must retain the above copyright 4654263Sshin * notice, this list of conditions and the following disclaimer. 4754263Sshin * 2. Redistributions in binary form must reproduce the above copyright 4854263Sshin * notice, this list of conditions and the following disclaimer in the 4954263Sshin * documentation and/or other materials provided with the distribution. 5054263Sshin * 4. Neither the name of the University nor the names of its contributors 5154263Sshin * may be used to endorse or promote products derived from this software 5254263Sshin * without specific prior written permission. 5354263Sshin * 5454263Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5554263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5654263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5754263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5854263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5954263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6054263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6154263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6254263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6354263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6454263Sshin * SUCH DAMAGE. 6554263Sshin * 66172087Srwatson * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 6754263Sshin */ 6854263Sshin 69174510Sobrien#include <sys/cdefs.h> 70174510Sobrien__FBSDID("$FreeBSD$"); 71174510Sobrien 7262587Sitojun#include "opt_inet.h" 7362587Sitojun#include "opt_inet6.h" 74225044Sbz#include "opt_ipfw.h" 7555009Sshin#include "opt_ipsec.h" 7655009Sshin 7754263Sshin#include <sys/param.h> 78185435Sbz#include <sys/jail.h> 7954263Sshin#include <sys/kernel.h> 8095759Stanimura#include <sys/lock.h> 8154263Sshin#include <sys/mbuf.h> 82164033Srwatson#include <sys/priv.h> 8395759Stanimura#include <sys/proc.h> 8454263Sshin#include <sys/protosw.h> 8595759Stanimura#include <sys/signalvar.h> 8654263Sshin#include <sys/socket.h> 8754263Sshin#include <sys/socketvar.h> 8895759Stanimura#include <sys/sx.h> 8954263Sshin#include <sys/sysctl.h> 9095759Stanimura#include <sys/syslog.h> 9154263Sshin#include <sys/systm.h> 9254263Sshin 9354263Sshin#include <net/if.h> 9495759Stanimura#include <net/if_types.h> 9554263Sshin#include <net/route.h> 9654263Sshin 9754263Sshin#include <netinet/in.h> 9895759Stanimura#include <netinet/in_pcb.h> 9954263Sshin#include <netinet/in_systm.h> 10095759Stanimura#include <netinet/in_var.h> 10154263Sshin#include <netinet/ip.h> 102171508Srwatson#include <netinet/ip_icmp.h> 10395759Stanimura#include <netinet/ip6.h> 104171508Srwatson#include <netinet/icmp_var.h> 10595759Stanimura#include <netinet/icmp6.h> 10654263Sshin#include <netinet/ip_var.h> 10754263Sshin#include <netinet/udp.h> 10854263Sshin#include <netinet/udp_var.h> 109185571Sbz 11095759Stanimura#include <netinet6/ip6protosw.h> 11154263Sshin#include <netinet6/ip6_var.h> 11254263Sshin#include <netinet6/in6_pcb.h> 11354263Sshin#include <netinet6/udp6_var.h> 114148385Sume#include <netinet6/scope6_var.h> 11554263Sshin 116171167Sgnn#ifdef IPSEC 117105199Ssam#include <netipsec/ipsec.h> 118105199Ssam#include <netipsec/ipsec6.h> 119171167Sgnn#endif /* IPSEC */ 120105199Ssam 121171508Srwatson#include <security/mac/mac_framework.h> 122171508Srwatson 12354263Sshin/* 124172087Srwatson * UDP protocol implementation. 12554263Sshin * Per RFC 768, August, 1980. 12654263Sshin */ 12754263Sshin 128171328Srwatsonextern struct protosw inetsw[]; 129171328Srwatsonstatic void udp6_detach(struct socket *so); 13054263Sshin 131158237Srwatsonstatic void 132172087Srwatsonudp6_append(struct inpcb *inp, struct mbuf *n, int off, 133158237Srwatson struct sockaddr_in6 *fromsa) 134158237Srwatson{ 135158237Srwatson struct socket *so; 136158237Srwatson struct mbuf *opts; 137158237Srwatson 138178419Srwatson INP_LOCK_ASSERT(inp); 139158237Srwatson 140171167Sgnn#ifdef IPSEC 141171328Srwatson /* Check AH/ESP integrity. */ 142172087Srwatson if (ipsec6_in_reject(n, inp)) { 143158237Srwatson m_freem(n); 144252692Sae IPSEC6STAT_INC(in_polvio); 145158237Srwatson return; 146158237Srwatson } 147171167Sgnn#endif /* IPSEC */ 148171508Srwatson#ifdef MAC 149172930Srwatson if (mac_inpcb_check_deliver(inp, n) != 0) { 150171508Srwatson m_freem(n); 151171508Srwatson return; 152171508Srwatson } 153171508Srwatson#endif 154158237Srwatson opts = NULL; 155186223Sbz if (inp->inp_flags & INP_CONTROLOPTS || 156172087Srwatson inp->inp_socket->so_options & SO_TIMESTAMP) 157172087Srwatson ip6_savecontrol(inp, n, &opts); 158158237Srwatson m_adj(n, off + sizeof(struct udphdr)); 159158237Srwatson 160172087Srwatson so = inp->inp_socket; 161158237Srwatson SOCKBUF_LOCK(&so->so_rcv); 162158237Srwatson if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n, 163158237Srwatson opts) == 0) { 164158237Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 165158237Srwatson m_freem(n); 166158237Srwatson if (opts) 167158237Srwatson m_freem(opts); 168190963Srwatson UDPSTAT_INC(udps_fullsock); 169158237Srwatson } else 170158237Srwatson sorwakeup_locked(so); 171158237Srwatson} 172158237Srwatson 17354263Sshinint 174171259Sdelphijudp6_input(struct mbuf **mp, int *offp, int proto) 17554263Sshin{ 176158237Srwatson struct mbuf *m = *mp; 177191672Sbms struct ifnet *ifp; 178171328Srwatson struct ip6_hdr *ip6; 179171328Srwatson struct udphdr *uh; 180172087Srwatson struct inpcb *inp; 181192649Sbz struct udpcb *up; 18254263Sshin int off = *offp; 18354263Sshin int plen, ulen; 184121901Sume struct sockaddr_in6 fromsa; 185225044Sbz struct m_tag *fwd_tag; 186238235Sbz uint16_t uh_sum; 18754263Sshin 188191672Sbms ifp = m->m_pkthdr.rcvif; 18978064Sume ip6 = mtod(m, struct ip6_hdr *); 19078064Sume 19183934Sbrooks if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 19278064Sume /* XXX send icmp6 host/port unreach? */ 19378064Sume m_freem(m); 194171328Srwatson return (IPPROTO_DONE); 19554263Sshin } 19678064Sume 197125777Sume#ifndef PULLDOWN_TEST 198125777Sume IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 199125777Sume ip6 = mtod(m, struct ip6_hdr *); 200125777Sume uh = (struct udphdr *)((caddr_t)ip6 + off); 201125777Sume#else 202125777Sume IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); 203125777Sume if (!uh) 204171328Srwatson return (IPPROTO_DONE); 205125777Sume#endif 206125777Sume 207190963Srwatson UDPSTAT_INC(udps_ipackets); 20854263Sshin 209171508Srwatson /* 210171508Srwatson * Destination port of 0 is illegal, based on RFC768. 211171508Srwatson */ 212171508Srwatson if (uh->uh_dport == 0) 213171508Srwatson goto badunlocked; 214171508Srwatson 21554263Sshin plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 21654263Sshin ulen = ntohs((u_short)uh->uh_ulen); 21754263Sshin 21854263Sshin if (plen != ulen) { 219190963Srwatson UDPSTAT_INC(udps_badlen); 220171328Srwatson goto badunlocked; 22154263Sshin } 22254263Sshin 22354263Sshin /* 22454263Sshin * Checksum extended UDP header and data. 22554263Sshin */ 226127711Ssuz if (uh->uh_sum == 0) { 227190963Srwatson UDPSTAT_INC(udps_nosum); 228171328Srwatson goto badunlocked; 229127711Ssuz } 230238235Sbz 231238247Sbz if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) { 232238235Sbz if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 233238235Sbz uh_sum = m->m_pkthdr.csum_data; 234238235Sbz else 235238235Sbz uh_sum = in6_cksum_pseudo(ip6, ulen, 236238235Sbz IPPROTO_UDP, m->m_pkthdr.csum_data); 237238235Sbz uh_sum ^= 0xffff; 238238235Sbz } else 239238235Sbz uh_sum = in6_cksum(m, IPPROTO_UDP, off, ulen); 240238235Sbz 241238235Sbz if (uh_sum != 0) { 242190963Srwatson UDPSTAT_INC(udps_badsum); 243171328Srwatson goto badunlocked; 24454263Sshin } 24554263Sshin 246158237Srwatson /* 247158237Srwatson * Construct sockaddr format source address. 248158237Srwatson */ 249158237Srwatson init_sin6(&fromsa, m); 250158237Srwatson fromsa.sin6_port = uh->uh_sport; 251158237Srwatson 25254263Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 253171328Srwatson struct inpcb *last; 254191672Sbms struct ip6_moptions *imo; 25554263Sshin 256222488Srwatson INP_INFO_RLOCK(&V_udbinfo); 25754263Sshin /* 258171328Srwatson * In the event that laddr should be set to the link-local 25954263Sshin * address (this happens in RIPng), the multicast address 260171328Srwatson * specified in the received packet will not match laddr. To 261171328Srwatson * handle this situation, matching is relaxed if the 262171328Srwatson * receiving interface is the same as one specified in the 263171328Srwatson * socket and if the destination multicast address matches 264171328Srwatson * one of the multicast groups specified in the socket. 26554263Sshin */ 26654263Sshin 26754263Sshin /* 268171328Srwatson * KAME note: traditionally we dropped udpiphdr from mbuf 269171328Srwatson * here. We need udphdr for IPsec processing so we do that 270171328Srwatson * later. 27154263Sshin */ 27254263Sshin last = NULL; 273181803Sbz LIST_FOREACH(inp, &V_udb, inp_list) { 274172087Srwatson if ((inp->inp_vflag & INP_IPV6) == 0) 27554263Sshin continue; 276186141Sbz if (inp->inp_lport != uh->uh_dport) 27754263Sshin continue; 278172087Srwatson if (inp->inp_fport != 0 && 279172087Srwatson inp->inp_fport != uh->uh_sport) 280171508Srwatson continue; 281172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 282172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, 283125777Sume &ip6->ip6_dst)) 28454263Sshin continue; 28554263Sshin } 286172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 287172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, 28854263Sshin &ip6->ip6_src) || 289186141Sbz inp->inp_fport != uh->uh_sport) 29054263Sshin continue; 29154263Sshin } 29254263Sshin 293191672Sbms /* 294222488Srwatson * XXXRW: Because we weren't holding either the inpcb 295222488Srwatson * or the hash lock when we checked for a match 296222488Srwatson * before, we should probably recheck now that the 297222488Srwatson * inpcb lock is (supposed to be) held. 298222488Srwatson */ 299222488Srwatson 300222488Srwatson /* 301191672Sbms * Handle socket delivery policy for any-source 302191672Sbms * and source-specific multicast. [RFC3678] 303191672Sbms */ 304191672Sbms imo = inp->in6p_moptions; 305191672Sbms if (imo && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 306191672Sbms struct sockaddr_in6 mcaddr; 307191672Sbms int blocked; 308191672Sbms 309191718Sbms INP_RLOCK(inp); 310191718Sbms 311191672Sbms bzero(&mcaddr, sizeof(struct sockaddr_in6)); 312191672Sbms mcaddr.sin6_len = sizeof(struct sockaddr_in6); 313191672Sbms mcaddr.sin6_family = AF_INET6; 314191672Sbms mcaddr.sin6_addr = ip6->ip6_dst; 315191672Sbms 316191672Sbms blocked = im6o_mc_filter(imo, ifp, 317191672Sbms (struct sockaddr *)&mcaddr, 318191672Sbms (struct sockaddr *)&fromsa); 319191672Sbms if (blocked != MCAST_PASS) { 320191672Sbms if (blocked == MCAST_NOTGMEMBER) 321191672Sbms IP6STAT_INC(ip6s_notmember); 322191672Sbms if (blocked == MCAST_NOTSMEMBER || 323191672Sbms blocked == MCAST_MUTED) 324191672Sbms UDPSTAT_INC(udps_filtermcast); 325191718Sbms INP_RUNLOCK(inp); /* XXX */ 326191672Sbms continue; 327191672Sbms } 328191718Sbms 329191718Sbms INP_RUNLOCK(inp); 330191672Sbms } 33154263Sshin if (last != NULL) { 332125777Sume struct mbuf *n; 33354263Sshin 33454263Sshin if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 335178419Srwatson INP_RLOCK(last); 336192649Sbz up = intoudpcb(last); 337192649Sbz if (up->u_tun_func == NULL) { 338192649Sbz udp6_append(last, n, off, &fromsa); 339192649Sbz } else { 340186813Srrs /* 341186813Srrs * Engage the tunneling 342186813Srrs * protocol we will have to 343186813Srrs * leave the info_lock up, 344186813Srrs * since we are hunting 345186821Srrs * through multiple UDP's. 346186813Srrs * 347186813Srrs */ 348192649Sbz (*up->u_tun_func)(n, off, last); 349186813Srrs } 350192649Sbz INP_RUNLOCK(last); 35154263Sshin } 35254263Sshin } 353172087Srwatson last = inp; 35454263Sshin /* 35554263Sshin * Don't look for additional matches if this one does 35654263Sshin * not have either the SO_REUSEPORT or SO_REUSEADDR 357171328Srwatson * socket options set. This heuristic avoids 358171328Srwatson * searching through all pcbs in the common case of a 359171328Srwatson * non-shared port. It assumes that an application 360171328Srwatson * will never clear these options after setting them. 36154263Sshin */ 362172087Srwatson if ((last->inp_socket->so_options & 36397658Stanimura (SO_REUSEPORT|SO_REUSEADDR)) == 0) 36454263Sshin break; 36554263Sshin } 36654263Sshin 36754263Sshin if (last == NULL) { 36854263Sshin /* 369171328Srwatson * No matching pcb found; discard datagram. (No need 370171328Srwatson * to send an ICMP Port Unreachable for a broadcast 371171328Srwatson * or multicast datgram.) 37254263Sshin */ 373190963Srwatson UDPSTAT_INC(udps_noport); 374190963Srwatson UDPSTAT_INC(udps_noportmcast); 375171328Srwatson goto badheadlocked; 37654263Sshin } 377178419Srwatson INP_RLOCK(last); 378182537Srwatson INP_INFO_RUNLOCK(&V_udbinfo); 379192649Sbz up = intoudpcb(last); 380192649Sbz if (up->u_tun_func == NULL) { 381192649Sbz udp6_append(last, m, off, &fromsa); 382192649Sbz } else { 383186813Srrs /* 384186821Srrs * Engage the tunneling protocol. 385186813Srrs */ 386192649Sbz (*up->u_tun_func)(m, off, last); 387186813Srrs } 388178419Srwatson INP_RUNLOCK(last); 389171328Srwatson return (IPPROTO_DONE); 39054263Sshin } 39154263Sshin /* 39254263Sshin * Locate pcb for datagram. 39354263Sshin */ 394243586Sae 395225044Sbz /* 396225044Sbz * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. 397225044Sbz */ 398243586Sae if ((m->m_flags & M_IP6_NEXTHOP) && 399243586Sae (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 400225044Sbz struct sockaddr_in6 *next_hop6; 401225044Sbz 402225044Sbz next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); 403225044Sbz 404225044Sbz /* 405225044Sbz * Transparently forwarded. Pretend to be the destination. 406225044Sbz * Already got one like this? 407225044Sbz */ 408225044Sbz inp = in6_pcblookup_mbuf(&V_udbinfo, 409225044Sbz &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 410225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); 411225044Sbz if (!inp) { 412225044Sbz /* 413225044Sbz * It's new. Try to find the ambushing socket. 414225044Sbz * Because we've rewritten the destination address, 415225044Sbz * any hardware-generated hash is ignored. 416225044Sbz */ 417225044Sbz inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src, 418225044Sbz uh->uh_sport, &next_hop6->sin6_addr, 419225044Sbz next_hop6->sin6_port ? htons(next_hop6->sin6_port) : 420225044Sbz uh->uh_dport, INPLOOKUP_WILDCARD | 421225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); 422225044Sbz } 423225044Sbz /* Remove the tag from the packet. We don't need it anymore. */ 424225044Sbz m_tag_delete(m, fwd_tag); 425243586Sae m->m_flags &= ~M_IP6_NEXTHOP; 426225044Sbz } else 427225044Sbz inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src, 428225044Sbz uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 429225044Sbz INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, 430225044Sbz m->m_pkthdr.rcvif, m); 431172087Srwatson if (inp == NULL) { 432166842Srwatson if (udp_log_in_vain) { 433165118Sbz char ip6bufs[INET6_ADDRSTRLEN]; 434165118Sbz char ip6bufd[INET6_ADDRSTRLEN]; 43554263Sshin 43654263Sshin log(LOG_INFO, 437102131Sjmallett "Connection attempt to UDP [%s]:%d from [%s]:%d\n", 438165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), 439165118Sbz ntohs(uh->uh_dport), 440165118Sbz ip6_sprintf(ip6bufs, &ip6->ip6_src), 441165118Sbz ntohs(uh->uh_sport)); 44254263Sshin } 443190963Srwatson UDPSTAT_INC(udps_noport); 44454263Sshin if (m->m_flags & M_MCAST) { 44554263Sshin printf("UDP6: M_MCAST is set in a unicast packet.\n"); 446190963Srwatson UDPSTAT_INC(udps_noportmcast); 447222488Srwatson goto badunlocked; 44854263Sshin } 449181803Sbz if (V_udp_blackhole) 450171508Srwatson goto badunlocked; 451171508Srwatson if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0) 452171508Srwatson goto badunlocked; 45354263Sshin icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 454171328Srwatson return (IPPROTO_DONE); 45554263Sshin } 456222488Srwatson INP_RLOCK_ASSERT(inp); 457192649Sbz up = intoudpcb(inp); 458192649Sbz if (up->u_tun_func == NULL) { 459192649Sbz udp6_append(inp, m, off, &fromsa); 460192649Sbz } else { 461186813Srrs /* 462186821Srrs * Engage the tunneling protocol. 463186813Srrs */ 464186813Srrs 465192649Sbz (*up->u_tun_func)(m, off, inp); 466186813Srrs } 467178419Srwatson INP_RUNLOCK(inp); 468171328Srwatson return (IPPROTO_DONE); 469171508Srwatson 470171328Srwatsonbadheadlocked: 471181803Sbz INP_INFO_RUNLOCK(&V_udbinfo); 472171328Srwatsonbadunlocked: 47354263Sshin if (m) 47454263Sshin m_freem(m); 475171328Srwatson return (IPPROTO_DONE); 47654263Sshin} 47754263Sshin 47854263Sshinvoid 479171259Sdelphijudp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 48054263Sshin{ 48154263Sshin struct udphdr uh; 48254263Sshin struct ip6_hdr *ip6; 48354263Sshin struct mbuf *m; 48462587Sitojun int off = 0; 48578064Sume struct ip6ctlparam *ip6cp = NULL; 48678064Sume const struct sockaddr_in6 *sa6_src = NULL; 487125776Sume void *cmdarg; 488175162Sobrien struct inpcb *(*notify)(struct inpcb *, int) = udp_notify; 48978064Sume struct udp_portonly { 49078064Sume u_int16_t uh_sport; 49178064Sume u_int16_t uh_dport; 49278064Sume } *uhp; 49354263Sshin 49454263Sshin if (sa->sa_family != AF_INET6 || 49554263Sshin sa->sa_len != sizeof(struct sockaddr_in6)) 49654263Sshin return; 49754263Sshin 49862587Sitojun if ((unsigned)cmd >= PRC_NCMDS) 49954263Sshin return; 50062587Sitojun if (PRC_IS_REDIRECT(cmd)) 50162587Sitojun notify = in6_rtchange, d = NULL; 50262587Sitojun else if (cmd == PRC_HOSTDEAD) 50362587Sitojun d = NULL; 50462587Sitojun else if (inet6ctlerrmap[cmd] == 0) 50562587Sitojun return; 50654263Sshin 50754263Sshin /* if the parameter is from icmp6, decode it. */ 50854263Sshin if (d != NULL) { 50978064Sume ip6cp = (struct ip6ctlparam *)d; 51054263Sshin m = ip6cp->ip6c_m; 51154263Sshin ip6 = ip6cp->ip6c_ip6; 51254263Sshin off = ip6cp->ip6c_off; 513125776Sume cmdarg = ip6cp->ip6c_cmdarg; 51478064Sume sa6_src = ip6cp->ip6c_src; 51554263Sshin } else { 51654263Sshin m = NULL; 51754263Sshin ip6 = NULL; 518125776Sume cmdarg = NULL; 51978064Sume sa6_src = &sa6_any; 52054263Sshin } 52154263Sshin 52254263Sshin if (ip6) { 52354263Sshin /* 52454263Sshin * XXX: We assume that when IPV6 is non NULL, 52554263Sshin * M and OFF are valid. 52654263Sshin */ 52754263Sshin 528171328Srwatson /* Check if we can safely examine src and dst ports. */ 52978064Sume if (m->m_pkthdr.len < off + sizeof(*uhp)) 53067456Sitojun return; 53167456Sitojun 53278064Sume bzero(&uh, sizeof(uh)); 53378064Sume m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 53478064Sume 535181803Sbz (void) in6_pcbnotify(&V_udbinfo, sa, uh.uh_dport, 536171328Srwatson (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd, 537171328Srwatson cmdarg, notify); 53854263Sshin } else 539181803Sbz (void) in6_pcbnotify(&V_udbinfo, sa, 0, 540171328Srwatson (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify); 54154263Sshin} 54254263Sshin 54354263Sshinstatic int 54462573Sphkudp6_getcred(SYSCTL_HANDLER_ARGS) 54554263Sshin{ 54672650Sgreen struct xucred xuc; 54754263Sshin struct sockaddr_in6 addrs[2]; 54854263Sshin struct inpcb *inp; 549157674Srwatson int error; 55054263Sshin 551170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 55254263Sshin if (error) 55354263Sshin return (error); 55462587Sitojun 55562587Sitojun if (req->newlen != sizeof(addrs)) 55662587Sitojun return (EINVAL); 55772650Sgreen if (req->oldlen != sizeof(struct xucred)) 55862587Sitojun return (EINVAL); 55954263Sshin error = SYSCTL_IN(req, addrs, sizeof(addrs)); 56054263Sshin if (error) 56154263Sshin return (error); 562181803Sbz if ((error = sa6_embedscope(&addrs[0], V_ip6_use_defzone)) != 0 || 563181803Sbz (error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) { 564148385Sume return (error); 565148385Sume } 566222488Srwatson inp = in6_pcblookup(&V_udbinfo, &addrs[1].sin6_addr, 567222488Srwatson addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 568222488Srwatson INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); 569179412Srwatson if (inp != NULL) { 570222488Srwatson INP_RLOCK_ASSERT(inp); 571179412Srwatson if (inp->inp_socket == NULL) 572179412Srwatson error = ENOENT; 573179412Srwatson if (error == 0) 574179412Srwatson error = cr_canseesocket(req->td->td_ucred, 575179412Srwatson inp->inp_socket); 576179412Srwatson if (error == 0) 577183606Sbz cru2x(inp->inp_cred, &xuc); 578179412Srwatson INP_RUNLOCK(inp); 579222488Srwatson } else 580171609Srwatson error = ENOENT; 581171609Srwatson if (error == 0) 582171609Srwatson error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 58354263Sshin return (error); 58454263Sshin} 58554263Sshin 586171328SrwatsonSYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 587171328Srwatson 0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); 58854263Sshin 589171552Srwatsonstatic int 590172087Srwatsonudp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, 591171552Srwatson struct mbuf *control, struct thread *td) 592171552Srwatson{ 593171552Srwatson u_int32_t ulen = m->m_pkthdr.len; 594171552Srwatson u_int32_t plen = sizeof(struct udphdr) + ulen; 595171552Srwatson struct ip6_hdr *ip6; 596171552Srwatson struct udphdr *udp6; 597194777Sbz struct in6_addr *laddr, *faddr, in6a; 598171552Srwatson struct sockaddr_in6 *sin6 = NULL; 599171552Srwatson struct ifnet *oifp = NULL; 600171552Srwatson int scope_ambiguous = 0; 601171552Srwatson u_short fport; 602171552Srwatson int error = 0; 603171552Srwatson struct ip6_pktopts *optp, opt; 604171552Srwatson int af = AF_INET6, hlen = sizeof(struct ip6_hdr); 605171552Srwatson int flags; 606171552Srwatson struct sockaddr_in6 tmp; 607171552Srwatson 608178285Srwatson INP_WLOCK_ASSERT(inp); 609222488Srwatson INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); 610171552Srwatson 611171552Srwatson if (addr6) { 612171552Srwatson /* addr6 has been validated in udp6_send(). */ 613171552Srwatson sin6 = (struct sockaddr_in6 *)addr6; 614171552Srwatson 615171552Srwatson /* protect *sin6 from overwrites */ 616171552Srwatson tmp = *sin6; 617171552Srwatson sin6 = &tmp; 618171552Srwatson 619171552Srwatson /* 620171552Srwatson * Application should provide a proper zone ID or the use of 621171552Srwatson * default zone IDs should be enabled. Unfortunately, some 622171552Srwatson * applications do not behave as it should, so we need a 623171552Srwatson * workaround. Even if an appropriate ID is not determined, 624171552Srwatson * we'll see if we can determine the outgoing interface. If we 625171552Srwatson * can, determine the zone ID based on the interface below. 626171552Srwatson */ 627181803Sbz if (sin6->sin6_scope_id == 0 && !V_ip6_use_defzone) 628171552Srwatson scope_ambiguous = 1; 629181803Sbz if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) 630171552Srwatson return (error); 631171552Srwatson } 632171552Srwatson 633171552Srwatson if (control) { 634171552Srwatson if ((error = ip6_setpktopts(control, &opt, 635175630Sbz inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0) 636171552Srwatson goto release; 637171552Srwatson optp = &opt; 638171552Srwatson } else 639172087Srwatson optp = inp->in6p_outputopts; 640171552Srwatson 641171552Srwatson if (sin6) { 642171552Srwatson faddr = &sin6->sin6_addr; 643171552Srwatson 644171552Srwatson /* 645171552Srwatson * IPv4 version of udp_output calls in_pcbconnect in this case, 646171552Srwatson * which needs splnet and affects performance. 647171552Srwatson * Since we saw no essential reason for calling in_pcbconnect, 648171552Srwatson * we get rid of such kind of logic, and call in6_selectsrc 649171552Srwatson * and in6_pcbsetport in order to fill in the local address 650171552Srwatson * and the local port. 651171552Srwatson */ 652171552Srwatson if (sin6->sin6_port == 0) { 653171552Srwatson error = EADDRNOTAVAIL; 654171552Srwatson goto release; 655171552Srwatson } 656171552Srwatson 657172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 658171552Srwatson /* how about ::ffff:0.0.0.0 case? */ 659171552Srwatson error = EISCONN; 660171552Srwatson goto release; 661171552Srwatson } 662171552Srwatson 663171552Srwatson fport = sin6->sin6_port; /* allow 0 port */ 664171552Srwatson 665171552Srwatson if (IN6_IS_ADDR_V4MAPPED(faddr)) { 666186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 667171552Srwatson /* 668171552Srwatson * I believe we should explicitly discard the 669171552Srwatson * packet when mapped addresses are disabled, 670171552Srwatson * rather than send the packet as an IPv6 one. 671171552Srwatson * If we chose the latter approach, the packet 672171552Srwatson * might be sent out on the wire based on the 673171552Srwatson * default route, the situation which we'd 674171552Srwatson * probably want to avoid. 675171552Srwatson * (20010421 jinmei@kame.net) 676171552Srwatson */ 677171552Srwatson error = EINVAL; 678171552Srwatson goto release; 679171552Srwatson } 680172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && 681172087Srwatson !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) { 682171552Srwatson /* 683171552Srwatson * when remote addr is an IPv4-mapped address, 684171552Srwatson * local addr should not be an IPv6 address, 685171552Srwatson * since you cannot determine how to map IPv6 686171552Srwatson * source address to IPv4. 687171552Srwatson */ 688171552Srwatson error = EINVAL; 689171552Srwatson goto release; 690171552Srwatson } 691171552Srwatson 692171552Srwatson af = AF_INET; 693171552Srwatson } 694171552Srwatson 695171552Srwatson if (!IN6_IS_ADDR_V4MAPPED(faddr)) { 696194777Sbz error = in6_selectsrc(sin6, optp, inp, NULL, 697194777Sbz td->td_ucred, &oifp, &in6a); 698194777Sbz if (error) 699194777Sbz goto release; 700171552Srwatson if (oifp && scope_ambiguous && 701171552Srwatson (error = in6_setscope(&sin6->sin6_addr, 702171552Srwatson oifp, NULL))) { 703171552Srwatson goto release; 704171552Srwatson } 705194777Sbz laddr = &in6a; 706171552Srwatson } else 707172087Srwatson laddr = &inp->in6p_laddr; /* XXX */ 708171552Srwatson if (laddr == NULL) { 709171552Srwatson if (error == 0) 710171552Srwatson error = EADDRNOTAVAIL; 711171552Srwatson goto release; 712171552Srwatson } 713186141Sbz if (inp->inp_lport == 0 && 714219570Sbz (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) { 715219570Sbz /* Undo an address bind that may have occurred. */ 716219570Sbz inp->in6p_laddr = in6addr_any; 717171552Srwatson goto release; 718219570Sbz } 719171552Srwatson } else { 720172087Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 721171552Srwatson error = ENOTCONN; 722171552Srwatson goto release; 723171552Srwatson } 724172087Srwatson if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { 725186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 726171552Srwatson /* 727171552Srwatson * XXX: this case would happen when the 728171552Srwatson * application sets the V6ONLY flag after 729171552Srwatson * connecting the foreign address. 730171552Srwatson * Such applications should be fixed, 731171552Srwatson * so we bark here. 732171552Srwatson */ 733171552Srwatson log(LOG_INFO, "udp6_output: IPV6_V6ONLY " 734171552Srwatson "option was set for a connected socket\n"); 735171552Srwatson error = EINVAL; 736171552Srwatson goto release; 737171552Srwatson } else 738171552Srwatson af = AF_INET; 739171552Srwatson } 740172087Srwatson laddr = &inp->in6p_laddr; 741172087Srwatson faddr = &inp->in6p_faddr; 742186141Sbz fport = inp->inp_fport; 743171552Srwatson } 744171552Srwatson 745171552Srwatson if (af == AF_INET) 746171552Srwatson hlen = sizeof(struct ip); 747171552Srwatson 748171552Srwatson /* 749171552Srwatson * Calculate data length and get a mbuf 750171552Srwatson * for UDP and IP6 headers. 751171552Srwatson */ 752171552Srwatson M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT); 753171552Srwatson if (m == 0) { 754171552Srwatson error = ENOBUFS; 755171552Srwatson goto release; 756171552Srwatson } 757171552Srwatson 758171552Srwatson /* 759171552Srwatson * Stuff checksum and output datagram. 760171552Srwatson */ 761171552Srwatson udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); 762186141Sbz udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ 763171552Srwatson udp6->uh_dport = fport; 764171552Srwatson if (plen <= 0xffff) 765171552Srwatson udp6->uh_ulen = htons((u_short)plen); 766171552Srwatson else 767171552Srwatson udp6->uh_ulen = 0; 768171552Srwatson udp6->uh_sum = 0; 769171552Srwatson 770171552Srwatson switch (af) { 771171552Srwatson case AF_INET6: 772171552Srwatson ip6 = mtod(m, struct ip6_hdr *); 773186141Sbz ip6->ip6_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; 774171552Srwatson ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 775171552Srwatson ip6->ip6_vfc |= IPV6_VERSION; 776171552Srwatson#if 0 /* ip6_plen will be filled in ip6_output. */ 777171552Srwatson ip6->ip6_plen = htons((u_short)plen); 778171552Srwatson#endif 779171552Srwatson ip6->ip6_nxt = IPPROTO_UDP; 780172087Srwatson ip6->ip6_hlim = in6_selecthlim(inp, NULL); 781171552Srwatson ip6->ip6_src = *laddr; 782171552Srwatson ip6->ip6_dst = *faddr; 783171552Srwatson 784238235Sbz udp6->uh_sum = in6_cksum_pseudo(ip6, plen, IPPROTO_UDP, 0); 785238247Sbz m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; 786238235Sbz m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); 787171552Srwatson 788171552Srwatson flags = 0; 789171552Srwatson 790190963Srwatson UDPSTAT_INC(udps_opackets); 791172087Srwatson error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions, 792172087Srwatson NULL, inp); 793171552Srwatson break; 794171552Srwatson case AF_INET: 795171552Srwatson error = EAFNOSUPPORT; 796171552Srwatson goto release; 797171552Srwatson } 798171552Srwatson goto releaseopt; 799171552Srwatson 800171552Srwatsonrelease: 801171552Srwatson m_freem(m); 802171552Srwatson 803171552Srwatsonreleaseopt: 804171552Srwatson if (control) { 805171552Srwatson ip6_clearpktopts(&opt, -1); 806171552Srwatson m_freem(control); 807171552Srwatson } 808171552Srwatson return (error); 809171552Srwatson} 810171552Srwatson 811157366Srwatsonstatic void 81254263Sshinudp6_abort(struct socket *so) 81354263Sshin{ 81454263Sshin struct inpcb *inp; 81554263Sshin 816157374Srwatson inp = sotoinpcb(so); 817157374Srwatson KASSERT(inp != NULL, ("udp6_abort: inp == NULL")); 818157674Srwatson 819160549Srwatson#ifdef INET 820160549Srwatson if (inp->inp_vflag & INP_IPV4) { 821160549Srwatson struct pr_usrreqs *pru; 822160549Srwatson 823160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 824160549Srwatson (*pru->pru_abort)(so); 825160549Srwatson return; 826160549Srwatson } 827160549Srwatson#endif 828160549Srwatson 829178285Srwatson INP_WLOCK(inp); 830160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 831222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 832160549Srwatson in6_pcbdisconnect(inp); 833160549Srwatson inp->in6p_laddr = in6addr_any; 834222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 835160549Srwatson soisdisconnected(so); 836160549Srwatson } 837178285Srwatson INP_WUNLOCK(inp); 83854263Sshin} 83954263Sshin 84054263Sshinstatic int 84183366Sjulianudp6_attach(struct socket *so, int proto, struct thread *td) 84254263Sshin{ 84354263Sshin struct inpcb *inp; 844157674Srwatson int error; 84554263Sshin 84654263Sshin inp = sotoinpcb(so); 847157607Srwatson KASSERT(inp == NULL, ("udp6_attach: inp != NULL")); 848157674Srwatson 84954263Sshin if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 85054263Sshin error = soreserve(so, udp_sendspace, udp_recvspace); 851157374Srwatson if (error) 852171328Srwatson return (error); 85354263Sshin } 854181803Sbz INP_INFO_WLOCK(&V_udbinfo); 855181803Sbz error = in_pcballoc(so, &V_udbinfo); 856132714Srwatson if (error) { 857181803Sbz INP_INFO_WUNLOCK(&V_udbinfo); 858171328Srwatson return (error); 859132714Srwatson } 86054263Sshin inp = (struct inpcb *)so->so_pcb; 86154263Sshin inp->inp_vflag |= INP_IPV6; 862155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) 863100132Sume inp->inp_vflag |= INP_IPV4; 86454263Sshin inp->in6p_hops = -1; /* use kernel default */ 86554263Sshin inp->in6p_cksum = -1; /* just to be sure */ 86661958Sitojun /* 86761958Sitojun * XXX: ugly!! 86861958Sitojun * IPv4 TTL initialization is necessary for an IPv6 socket as well, 86961958Sitojun * because the socket may be bound to an IPv6 wildcard address, 87061958Sitojun * which may match an IPv4-mapped IPv6 address. 87161958Sitojun */ 872181803Sbz inp->inp_ip_ttl = V_ip_defttl; 873192649Sbz 874192649Sbz error = udp_newudpcb(inp); 875192649Sbz if (error) { 876192649Sbz in_pcbdetach(inp); 877192649Sbz in_pcbfree(inp); 878192649Sbz INP_INFO_WUNLOCK(&V_udbinfo); 879192649Sbz return (error); 880192649Sbz } 881178285Srwatson INP_WUNLOCK(inp); 882192649Sbz INP_INFO_WUNLOCK(&V_udbinfo); 883171328Srwatson return (0); 88454263Sshin} 88554263Sshin 88654263Sshinstatic int 88783366Sjulianudp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 88854263Sshin{ 88954263Sshin struct inpcb *inp; 890157674Srwatson int error; 89154263Sshin 892157374Srwatson inp = sotoinpcb(so); 893157374Srwatson KASSERT(inp != NULL, ("udp6_bind: inp == NULL")); 894157674Srwatson 895178285Srwatson INP_WLOCK(inp); 896222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 89754263Sshin inp->inp_vflag &= ~INP_IPV4; 89854263Sshin inp->inp_vflag |= INP_IPV6; 89978064Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 90054263Sshin struct sockaddr_in6 *sin6_p; 90154263Sshin 90254263Sshin sin6_p = (struct sockaddr_in6 *)nam; 90354263Sshin 90454263Sshin if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 90554263Sshin inp->inp_vflag |= INP_IPV4; 906221248Sbz#ifdef INET 90754263Sshin else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 90854263Sshin struct sockaddr_in sin; 90954263Sshin 91054263Sshin in6_sin6_2_sin(&sin, sin6_p); 91154263Sshin inp->inp_vflag |= INP_IPV4; 91254263Sshin inp->inp_vflag &= ~INP_IPV6; 913127505Spjd error = in_pcbbind(inp, (struct sockaddr *)&sin, 914127505Spjd td->td_ucred); 915132714Srwatson goto out; 91654263Sshin } 917221248Sbz#endif 91854263Sshin } 91954263Sshin 920127505Spjd error = in6_pcbbind(inp, nam, td->td_ucred); 921221248Sbz#ifdef INET 922132714Srwatsonout: 923221248Sbz#endif 924222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 925178285Srwatson INP_WUNLOCK(inp); 926171328Srwatson return (error); 92754263Sshin} 92854263Sshin 929160549Srwatsonstatic void 930160549Srwatsonudp6_close(struct socket *so) 931160549Srwatson{ 932160549Srwatson struct inpcb *inp; 933160549Srwatson 934160549Srwatson inp = sotoinpcb(so); 935160549Srwatson KASSERT(inp != NULL, ("udp6_close: inp == NULL")); 936160549Srwatson 937160549Srwatson#ifdef INET 938160549Srwatson if (inp->inp_vflag & INP_IPV4) { 939160549Srwatson struct pr_usrreqs *pru; 940160549Srwatson 941160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 942160549Srwatson (*pru->pru_disconnect)(so); 943160549Srwatson return; 944160549Srwatson } 945160549Srwatson#endif 946178285Srwatson INP_WLOCK(inp); 947160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 948222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 949160549Srwatson in6_pcbdisconnect(inp); 950160549Srwatson inp->in6p_laddr = in6addr_any; 951222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 952160549Srwatson soisdisconnected(so); 953160549Srwatson } 954178285Srwatson INP_WUNLOCK(inp); 955160549Srwatson} 956160549Srwatson 95754263Sshinstatic int 95883366Sjulianudp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 95954263Sshin{ 96054263Sshin struct inpcb *inp; 961188151Sjamie struct sockaddr_in6 *sin6; 962157674Srwatson int error; 96354263Sshin 964157374Srwatson inp = sotoinpcb(so); 965188151Sjamie sin6 = (struct sockaddr_in6 *)nam; 966157374Srwatson KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); 967157674Srwatson 968222488Srwatson /* 969222488Srwatson * XXXRW: Need to clarify locking of v4/v6 flags. 970222488Srwatson */ 971178285Srwatson INP_WLOCK(inp); 972221248Sbz#ifdef INET 973220462Sbz if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 974188151Sjamie struct sockaddr_in sin; 97554263Sshin 976220462Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { 977220462Sbz error = EINVAL; 978220462Sbz goto out; 979220462Sbz } 980188151Sjamie if (inp->inp_faddr.s_addr != INADDR_ANY) { 981188151Sjamie error = EISCONN; 982132714Srwatson goto out; 98354263Sshin } 984188151Sjamie in6_sin6_2_sin(&sin, sin6); 985220462Sbz inp->inp_vflag |= INP_IPV4; 986220462Sbz inp->inp_vflag &= ~INP_IPV6; 987188151Sjamie error = prison_remote_ip4(td->td_ucred, &sin.sin_addr); 988188151Sjamie if (error != 0) 989188151Sjamie goto out; 990222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 991188151Sjamie error = in_pcbconnect(inp, (struct sockaddr *)&sin, 992188151Sjamie td->td_ucred); 993222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 994220462Sbz if (error == 0) 995188151Sjamie soisconnected(so); 996188151Sjamie goto out; 99754263Sshin } 998221248Sbz#endif 999132714Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1000132714Srwatson error = EISCONN; 1001132714Srwatson goto out; 1002132714Srwatson } 1003220462Sbz inp->inp_vflag &= ~INP_IPV4; 1004220462Sbz inp->inp_vflag |= INP_IPV6; 1005188151Sjamie error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); 1006188151Sjamie if (error != 0) 1007188151Sjamie goto out; 1008222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 1009127505Spjd error = in6_pcbconnect(inp, nam, td->td_ucred); 1010222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1011220462Sbz if (error == 0) 101254263Sshin soisconnected(so); 1013132714Srwatsonout: 1014178285Srwatson INP_WUNLOCK(inp); 1015171328Srwatson return (error); 101654263Sshin} 101754263Sshin 1018157370Srwatsonstatic void 101954263Sshinudp6_detach(struct socket *so) 102054263Sshin{ 102154263Sshin struct inpcb *inp; 1022192649Sbz struct udpcb *up; 102354263Sshin 1024157374Srwatson inp = sotoinpcb(so); 1025157374Srwatson KASSERT(inp != NULL, ("udp6_detach: inp == NULL")); 1026157674Srwatson 1027181803Sbz INP_INFO_WLOCK(&V_udbinfo); 1028178285Srwatson INP_WLOCK(inp); 1029192649Sbz up = intoudpcb(inp); 1030192649Sbz KASSERT(up != NULL, ("%s: up == NULL", __func__)); 1031185344Sbz in_pcbdetach(inp); 1032185370Sbz in_pcbfree(inp); 1033181803Sbz INP_INFO_WUNLOCK(&V_udbinfo); 1034192649Sbz udp_discardcb(up); 103554263Sshin} 103654263Sshin 103754263Sshinstatic int 103854263Sshinudp6_disconnect(struct socket *so) 103954263Sshin{ 104054263Sshin struct inpcb *inp; 1041157674Srwatson int error; 104254263Sshin 1043157374Srwatson inp = sotoinpcb(so); 1044157374Srwatson KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL")); 1045157674Srwatson 1046125777Sume#ifdef INET 104754263Sshin if (inp->inp_vflag & INP_IPV4) { 104854263Sshin struct pr_usrreqs *pru; 104954263Sshin 105054263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1051222488Srwatson (void)(*pru->pru_disconnect)(so); 1052222488Srwatson return (0); 105354263Sshin } 1054125777Sume#endif 105554263Sshin 1056222488Srwatson INP_WLOCK(inp); 1057222488Srwatson 1058132714Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1059132714Srwatson error = ENOTCONN; 1060132714Srwatson goto out; 1061132714Srwatson } 106254263Sshin 1063222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 106454263Sshin in6_pcbdisconnect(inp); 106554263Sshin inp->in6p_laddr = in6addr_any; 1066222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1067183807Srwatson SOCK_LOCK(so); 106854263Sshin so->so_state &= ~SS_ISCONNECTED; /* XXX */ 1069183807Srwatson SOCK_UNLOCK(so); 1070132714Srwatsonout: 1071178285Srwatson INP_WUNLOCK(inp); 1072171328Srwatson return (0); 107354263Sshin} 107454263Sshin 107554263Sshinstatic int 1076171328Srwatsonudp6_send(struct socket *so, int flags, struct mbuf *m, 1077171328Srwatson struct sockaddr *addr, struct mbuf *control, struct thread *td) 107854263Sshin{ 107954263Sshin struct inpcb *inp; 108062587Sitojun int error = 0; 108154263Sshin 1082157374Srwatson inp = sotoinpcb(so); 1083157374Srwatson KASSERT(inp != NULL, ("udp6_send: inp == NULL")); 1084157674Srwatson 1085178285Srwatson INP_WLOCK(inp); 108662587Sitojun if (addr) { 1087171260Sdelphij if (addr->sa_len != sizeof(struct sockaddr_in6)) { 108862587Sitojun error = EINVAL; 108962587Sitojun goto bad; 109062587Sitojun } 109162587Sitojun if (addr->sa_family != AF_INET6) { 109262587Sitojun error = EAFNOSUPPORT; 109362587Sitojun goto bad; 109462587Sitojun } 109562587Sitojun } 109662587Sitojun 1097125777Sume#ifdef INET 1098155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 109954263Sshin int hasv4addr; 110054263Sshin struct sockaddr_in6 *sin6 = 0; 110154263Sshin 110254263Sshin if (addr == 0) 110354263Sshin hasv4addr = (inp->inp_vflag & INP_IPV4); 110454263Sshin else { 110554263Sshin sin6 = (struct sockaddr_in6 *)addr; 110654263Sshin hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) 1107171328Srwatson ? 1 : 0; 110854263Sshin } 110954263Sshin if (hasv4addr) { 111054263Sshin struct pr_usrreqs *pru; 111154263Sshin 1112183265Srwatson /* 1113183265Srwatson * XXXRW: We release UDP-layer locks before calling 1114183265Srwatson * udp_send() in order to avoid recursion. However, 1115183265Srwatson * this does mean there is a short window where inp's 1116183265Srwatson * fields are unstable. Could this lead to a 1117183265Srwatson * potential race in which the factors causing us to 1118183265Srwatson * select the UDPv4 output routine are invalidated? 1119183265Srwatson */ 1120183265Srwatson INP_WUNLOCK(inp); 112154263Sshin if (sin6) 112254263Sshin in6_sin6_2_sin_in_sock(addr); 112354263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1124183265Srwatson /* addr will just be freed in sendit(). */ 1125183265Srwatson return ((*pru->pru_send)(so, flags, m, addr, control, 1126171328Srwatson td)); 112754263Sshin } 112854263Sshin } 1129125777Sume#endif 1130171508Srwatson#ifdef MAC 1131172930Srwatson mac_inpcb_create_mbuf(inp, m); 1132171508Srwatson#endif 1133222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 1134132714Srwatson error = udp6_output(inp, m, addr, control, td); 1135222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1136207828Skmacy#ifdef INET 1137207828Skmacy#endif 1138178285Srwatson INP_WUNLOCK(inp); 1139171328Srwatson return (error); 114062587Sitojun 1141171328Srwatsonbad: 1142178285Srwatson INP_WUNLOCK(inp); 114362587Sitojun m_freem(m); 1144120856Sume return (error); 114554263Sshin} 114654263Sshin 114754263Sshinstruct pr_usrreqs udp6_usrreqs = { 1148137386Sphk .pru_abort = udp6_abort, 1149137386Sphk .pru_attach = udp6_attach, 1150137386Sphk .pru_bind = udp6_bind, 1151137386Sphk .pru_connect = udp6_connect, 1152137386Sphk .pru_control = in6_control, 1153137386Sphk .pru_detach = udp6_detach, 1154137386Sphk .pru_disconnect = udp6_disconnect, 1155137386Sphk .pru_peeraddr = in6_mapped_peeraddr, 1156137386Sphk .pru_send = udp6_send, 1157137386Sphk .pru_shutdown = udp_shutdown, 1158137386Sphk .pru_sockaddr = in6_mapped_sockaddr, 1159180365Srwatson .pru_soreceive = soreceive_dgram, 1160180365Srwatson .pru_sosend = sosend_dgram, 1161160549Srwatson .pru_sosetlabel = in_pcbsosetlabel, 1162160549Srwatson .pru_close = udp6_close 116354263Sshin}; 1164