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" 76254889Smarkj#include "opt_kdtrace.h" 7755009Sshin 7854263Sshin#include <sys/param.h> 79185435Sbz#include <sys/jail.h> 8054263Sshin#include <sys/kernel.h> 8195759Stanimura#include <sys/lock.h> 8254263Sshin#include <sys/mbuf.h> 83164033Srwatson#include <sys/priv.h> 8495759Stanimura#include <sys/proc.h> 8554263Sshin#include <sys/protosw.h> 86254889Smarkj#include <sys/sdt.h> 8795759Stanimura#include <sys/signalvar.h> 8854263Sshin#include <sys/socket.h> 8954263Sshin#include <sys/socketvar.h> 9095759Stanimura#include <sys/sx.h> 9154263Sshin#include <sys/sysctl.h> 9295759Stanimura#include <sys/syslog.h> 9354263Sshin#include <sys/systm.h> 9454263Sshin 9554263Sshin#include <net/if.h> 9695759Stanimura#include <net/if_types.h> 9754263Sshin#include <net/route.h> 9854263Sshin 9954263Sshin#include <netinet/in.h> 100254889Smarkj#include <netinet/in_kdtrace.h> 10195759Stanimura#include <netinet/in_pcb.h> 10254263Sshin#include <netinet/in_systm.h> 10395759Stanimura#include <netinet/in_var.h> 10454263Sshin#include <netinet/ip.h> 105171508Srwatson#include <netinet/ip_icmp.h> 10695759Stanimura#include <netinet/ip6.h> 107171508Srwatson#include <netinet/icmp_var.h> 10895759Stanimura#include <netinet/icmp6.h> 10954263Sshin#include <netinet/ip_var.h> 11054263Sshin#include <netinet/udp.h> 11154263Sshin#include <netinet/udp_var.h> 112185571Sbz 11395759Stanimura#include <netinet6/ip6protosw.h> 11454263Sshin#include <netinet6/ip6_var.h> 11554263Sshin#include <netinet6/in6_pcb.h> 11654263Sshin#include <netinet6/udp6_var.h> 117148385Sume#include <netinet6/scope6_var.h> 11854263Sshin 119171167Sgnn#ifdef IPSEC 120105199Ssam#include <netipsec/ipsec.h> 121105199Ssam#include <netipsec/ipsec6.h> 122171167Sgnn#endif /* IPSEC */ 123105199Ssam 124171508Srwatson#include <security/mac/mac_framework.h> 125171508Srwatson 12654263Sshin/* 127172087Srwatson * UDP protocol implementation. 12854263Sshin * Per RFC 768, August, 1980. 12954263Sshin */ 13054263Sshin 131171328Srwatsonextern struct protosw inetsw[]; 132171328Srwatsonstatic void udp6_detach(struct socket *so); 13354263Sshin 134158237Srwatsonstatic void 135172087Srwatsonudp6_append(struct inpcb *inp, struct mbuf *n, int off, 136158237Srwatson struct sockaddr_in6 *fromsa) 137158237Srwatson{ 138158237Srwatson struct socket *so; 139158237Srwatson struct mbuf *opts; 140158237Srwatson 141178419Srwatson INP_LOCK_ASSERT(inp); 142158237Srwatson 143171167Sgnn#ifdef IPSEC 144171328Srwatson /* Check AH/ESP integrity. */ 145172087Srwatson if (ipsec6_in_reject(n, inp)) { 146158237Srwatson m_freem(n); 147253571Sae IPSEC6STAT_INC(ips_in_polvio); 148158237Srwatson return; 149158237Srwatson } 150171167Sgnn#endif /* IPSEC */ 151171508Srwatson#ifdef MAC 152172930Srwatson if (mac_inpcb_check_deliver(inp, n) != 0) { 153171508Srwatson m_freem(n); 154171508Srwatson return; 155171508Srwatson } 156171508Srwatson#endif 157158237Srwatson opts = NULL; 158186223Sbz if (inp->inp_flags & INP_CONTROLOPTS || 159172087Srwatson inp->inp_socket->so_options & SO_TIMESTAMP) 160172087Srwatson ip6_savecontrol(inp, n, &opts); 161158237Srwatson m_adj(n, off + sizeof(struct udphdr)); 162158237Srwatson 163172087Srwatson so = inp->inp_socket; 164158237Srwatson SOCKBUF_LOCK(&so->so_rcv); 165158237Srwatson if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n, 166158237Srwatson opts) == 0) { 167158237Srwatson SOCKBUF_UNLOCK(&so->so_rcv); 168158237Srwatson m_freem(n); 169158237Srwatson if (opts) 170158237Srwatson m_freem(opts); 171190963Srwatson UDPSTAT_INC(udps_fullsock); 172158237Srwatson } else 173158237Srwatson sorwakeup_locked(so); 174158237Srwatson} 175158237Srwatson 17654263Sshinint 177171259Sdelphijudp6_input(struct mbuf **mp, int *offp, int proto) 17854263Sshin{ 179158237Srwatson struct mbuf *m = *mp; 180191672Sbms struct ifnet *ifp; 181171328Srwatson struct ip6_hdr *ip6; 182171328Srwatson struct udphdr *uh; 183172087Srwatson struct inpcb *inp; 184192649Sbz struct udpcb *up; 18554263Sshin int off = *offp; 18654263Sshin int plen, ulen; 187121901Sume struct sockaddr_in6 fromsa; 188225044Sbz struct m_tag *fwd_tag; 189235959Sbz uint16_t uh_sum; 19054263Sshin 191191672Sbms ifp = m->m_pkthdr.rcvif; 19278064Sume ip6 = mtod(m, struct ip6_hdr *); 19378064Sume 19483934Sbrooks if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 19578064Sume /* XXX send icmp6 host/port unreach? */ 19678064Sume m_freem(m); 197171328Srwatson return (IPPROTO_DONE); 19854263Sshin } 19978064Sume 200125777Sume#ifndef PULLDOWN_TEST 201125777Sume IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 202125777Sume ip6 = mtod(m, struct ip6_hdr *); 203125777Sume uh = (struct udphdr *)((caddr_t)ip6 + off); 204125777Sume#else 205125777Sume IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); 206125777Sume if (!uh) 207171328Srwatson return (IPPROTO_DONE); 208125777Sume#endif 209125777Sume 210190963Srwatson UDPSTAT_INC(udps_ipackets); 21154263Sshin 212171508Srwatson /* 213171508Srwatson * Destination port of 0 is illegal, based on RFC768. 214171508Srwatson */ 215171508Srwatson if (uh->uh_dport == 0) 216171508Srwatson goto badunlocked; 217171508Srwatson 21854263Sshin plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 21954263Sshin ulen = ntohs((u_short)uh->uh_ulen); 22054263Sshin 22154263Sshin if (plen != ulen) { 222190963Srwatson UDPSTAT_INC(udps_badlen); 223171328Srwatson goto badunlocked; 22454263Sshin } 22554263Sshin 22654263Sshin /* 22754263Sshin * Checksum extended UDP header and data. 22854263Sshin */ 229127711Ssuz if (uh->uh_sum == 0) { 230190963Srwatson UDPSTAT_INC(udps_nosum); 231171328Srwatson goto badunlocked; 232127711Ssuz } 233235959Sbz 234236170Sbz if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) { 235235959Sbz if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) 236235959Sbz uh_sum = m->m_pkthdr.csum_data; 237235959Sbz else 238235959Sbz uh_sum = in6_cksum_pseudo(ip6, ulen, 239235959Sbz IPPROTO_UDP, m->m_pkthdr.csum_data); 240235959Sbz uh_sum ^= 0xffff; 241235959Sbz } else 242235959Sbz uh_sum = in6_cksum(m, IPPROTO_UDP, off, ulen); 243235959Sbz 244235959Sbz if (uh_sum != 0) { 245190963Srwatson UDPSTAT_INC(udps_badsum); 246171328Srwatson goto badunlocked; 24754263Sshin } 24854263Sshin 249158237Srwatson /* 250158237Srwatson * Construct sockaddr format source address. 251158237Srwatson */ 252158237Srwatson init_sin6(&fromsa, m); 253158237Srwatson fromsa.sin6_port = uh->uh_sport; 254158237Srwatson 25554263Sshin if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 256171328Srwatson struct inpcb *last; 257191672Sbms struct ip6_moptions *imo; 25854263Sshin 259222488Srwatson INP_INFO_RLOCK(&V_udbinfo); 26054263Sshin /* 261171328Srwatson * In the event that laddr should be set to the link-local 26254263Sshin * address (this happens in RIPng), the multicast address 263171328Srwatson * specified in the received packet will not match laddr. To 264171328Srwatson * handle this situation, matching is relaxed if the 265171328Srwatson * receiving interface is the same as one specified in the 266171328Srwatson * socket and if the destination multicast address matches 267171328Srwatson * one of the multicast groups specified in the socket. 26854263Sshin */ 26954263Sshin 27054263Sshin /* 271171328Srwatson * KAME note: traditionally we dropped udpiphdr from mbuf 272171328Srwatson * here. We need udphdr for IPsec processing so we do that 273171328Srwatson * later. 27454263Sshin */ 27554263Sshin last = NULL; 276181803Sbz LIST_FOREACH(inp, &V_udb, inp_list) { 277172087Srwatson if ((inp->inp_vflag & INP_IPV6) == 0) 27854263Sshin continue; 279186141Sbz if (inp->inp_lport != uh->uh_dport) 28054263Sshin continue; 281172087Srwatson if (inp->inp_fport != 0 && 282172087Srwatson inp->inp_fport != uh->uh_sport) 283171508Srwatson continue; 284172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 285172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, 286125777Sume &ip6->ip6_dst)) 28754263Sshin continue; 28854263Sshin } 289172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 290172087Srwatson if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, 29154263Sshin &ip6->ip6_src) || 292186141Sbz inp->inp_fport != uh->uh_sport) 29354263Sshin continue; 29454263Sshin } 29554263Sshin 296191672Sbms /* 297222488Srwatson * XXXRW: Because we weren't holding either the inpcb 298222488Srwatson * or the hash lock when we checked for a match 299222488Srwatson * before, we should probably recheck now that the 300222488Srwatson * inpcb lock is (supposed to be) held. 301222488Srwatson */ 302222488Srwatson 303222488Srwatson /* 304191672Sbms * Handle socket delivery policy for any-source 305191672Sbms * and source-specific multicast. [RFC3678] 306191672Sbms */ 307191672Sbms imo = inp->in6p_moptions; 308191672Sbms if (imo && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 309191672Sbms struct sockaddr_in6 mcaddr; 310191672Sbms int blocked; 311191672Sbms 312191718Sbms INP_RLOCK(inp); 313191718Sbms 314191672Sbms bzero(&mcaddr, sizeof(struct sockaddr_in6)); 315191672Sbms mcaddr.sin6_len = sizeof(struct sockaddr_in6); 316191672Sbms mcaddr.sin6_family = AF_INET6; 317191672Sbms mcaddr.sin6_addr = ip6->ip6_dst; 318191672Sbms 319191672Sbms blocked = im6o_mc_filter(imo, ifp, 320191672Sbms (struct sockaddr *)&mcaddr, 321191672Sbms (struct sockaddr *)&fromsa); 322191672Sbms if (blocked != MCAST_PASS) { 323191672Sbms if (blocked == MCAST_NOTGMEMBER) 324191672Sbms IP6STAT_INC(ip6s_notmember); 325191672Sbms if (blocked == MCAST_NOTSMEMBER || 326191672Sbms blocked == MCAST_MUTED) 327191672Sbms UDPSTAT_INC(udps_filtermcast); 328191718Sbms INP_RUNLOCK(inp); /* XXX */ 329191672Sbms continue; 330191672Sbms } 331191718Sbms 332191718Sbms INP_RUNLOCK(inp); 333191672Sbms } 33454263Sshin if (last != NULL) { 335125777Sume struct mbuf *n; 33654263Sshin 33754263Sshin if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 338178419Srwatson INP_RLOCK(last); 339192649Sbz up = intoudpcb(last); 340192649Sbz if (up->u_tun_func == NULL) { 341192649Sbz udp6_append(last, n, off, &fromsa); 342192649Sbz } else { 343186813Srrs /* 344186813Srrs * Engage the tunneling 345186813Srrs * protocol we will have to 346186813Srrs * leave the info_lock up, 347186813Srrs * since we are hunting 348186821Srrs * through multiple UDP's. 349186813Srrs * 350186813Srrs */ 351192649Sbz (*up->u_tun_func)(n, off, last); 352186813Srrs } 353192649Sbz INP_RUNLOCK(last); 35454263Sshin } 35554263Sshin } 356172087Srwatson last = inp; 35754263Sshin /* 35854263Sshin * Don't look for additional matches if this one does 35954263Sshin * not have either the SO_REUSEPORT or SO_REUSEADDR 360171328Srwatson * socket options set. This heuristic avoids 361171328Srwatson * searching through all pcbs in the common case of a 362171328Srwatson * non-shared port. It assumes that an application 363171328Srwatson * will never clear these options after setting them. 36454263Sshin */ 365172087Srwatson if ((last->inp_socket->so_options & 36697658Stanimura (SO_REUSEPORT|SO_REUSEADDR)) == 0) 36754263Sshin break; 36854263Sshin } 36954263Sshin 37054263Sshin if (last == NULL) { 37154263Sshin /* 372171328Srwatson * No matching pcb found; discard datagram. (No need 373171328Srwatson * to send an ICMP Port Unreachable for a broadcast 374171328Srwatson * or multicast datgram.) 37554263Sshin */ 376190963Srwatson UDPSTAT_INC(udps_noport); 377190963Srwatson UDPSTAT_INC(udps_noportmcast); 378171328Srwatson goto badheadlocked; 37954263Sshin } 380178419Srwatson INP_RLOCK(last); 381182537Srwatson INP_INFO_RUNLOCK(&V_udbinfo); 382192649Sbz up = intoudpcb(last); 383254889Smarkj UDP_PROBE(receive, NULL, last, ip6, last, uh); 384192649Sbz if (up->u_tun_func == NULL) { 385192649Sbz udp6_append(last, m, off, &fromsa); 386192649Sbz } else { 387186813Srrs /* 388186821Srrs * Engage the tunneling protocol. 389186813Srrs */ 390192649Sbz (*up->u_tun_func)(m, off, last); 391186813Srrs } 392178419Srwatson INP_RUNLOCK(last); 393171328Srwatson return (IPPROTO_DONE); 39454263Sshin } 39554263Sshin /* 39654263Sshin * Locate pcb for datagram. 39754263Sshin */ 398242079Sae 399225044Sbz /* 400225044Sbz * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. 401225044Sbz */ 402242463Sae if ((m->m_flags & M_IP6_NEXTHOP) && 403242079Sae (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { 404225044Sbz struct sockaddr_in6 *next_hop6; 405225044Sbz 406225044Sbz next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); 407225044Sbz 408225044Sbz /* 409225044Sbz * Transparently forwarded. Pretend to be the destination. 410225044Sbz * Already got one like this? 411225044Sbz */ 412225044Sbz inp = in6_pcblookup_mbuf(&V_udbinfo, 413225044Sbz &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 414225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); 415225044Sbz if (!inp) { 416225044Sbz /* 417225044Sbz * It's new. Try to find the ambushing socket. 418225044Sbz * Because we've rewritten the destination address, 419225044Sbz * any hardware-generated hash is ignored. 420225044Sbz */ 421225044Sbz inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src, 422225044Sbz uh->uh_sport, &next_hop6->sin6_addr, 423225044Sbz next_hop6->sin6_port ? htons(next_hop6->sin6_port) : 424225044Sbz uh->uh_dport, INPLOOKUP_WILDCARD | 425225044Sbz INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); 426225044Sbz } 427225044Sbz /* Remove the tag from the packet. We don't need it anymore. */ 428225044Sbz m_tag_delete(m, fwd_tag); 429242463Sae m->m_flags &= ~M_IP6_NEXTHOP; 430225044Sbz } else 431225044Sbz inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src, 432225044Sbz uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, 433225044Sbz INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, 434225044Sbz m->m_pkthdr.rcvif, m); 435172087Srwatson if (inp == NULL) { 436166842Srwatson if (udp_log_in_vain) { 437165118Sbz char ip6bufs[INET6_ADDRSTRLEN]; 438165118Sbz char ip6bufd[INET6_ADDRSTRLEN]; 43954263Sshin 44054263Sshin log(LOG_INFO, 441102131Sjmallett "Connection attempt to UDP [%s]:%d from [%s]:%d\n", 442165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), 443165118Sbz ntohs(uh->uh_dport), 444165118Sbz ip6_sprintf(ip6bufs, &ip6->ip6_src), 445165118Sbz ntohs(uh->uh_sport)); 44654263Sshin } 447190963Srwatson UDPSTAT_INC(udps_noport); 44854263Sshin if (m->m_flags & M_MCAST) { 44954263Sshin printf("UDP6: M_MCAST is set in a unicast packet.\n"); 450190963Srwatson UDPSTAT_INC(udps_noportmcast); 451222488Srwatson goto badunlocked; 45254263Sshin } 453181803Sbz if (V_udp_blackhole) 454171508Srwatson goto badunlocked; 455171508Srwatson if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0) 456171508Srwatson goto badunlocked; 45754263Sshin icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 458171328Srwatson return (IPPROTO_DONE); 45954263Sshin } 460222488Srwatson INP_RLOCK_ASSERT(inp); 461192649Sbz up = intoudpcb(inp); 462254889Smarkj UDP_PROBE(receive, NULL, inp, ip6, inp, uh); 463192649Sbz if (up->u_tun_func == NULL) { 464192649Sbz udp6_append(inp, m, off, &fromsa); 465192649Sbz } else { 466186813Srrs /* 467186821Srrs * Engage the tunneling protocol. 468186813Srrs */ 469186813Srrs 470192649Sbz (*up->u_tun_func)(m, off, inp); 471186813Srrs } 472178419Srwatson INP_RUNLOCK(inp); 473171328Srwatson return (IPPROTO_DONE); 474171508Srwatson 475171328Srwatsonbadheadlocked: 476181803Sbz INP_INFO_RUNLOCK(&V_udbinfo); 477171328Srwatsonbadunlocked: 47854263Sshin if (m) 47954263Sshin m_freem(m); 480171328Srwatson return (IPPROTO_DONE); 48154263Sshin} 48254263Sshin 48354263Sshinvoid 484171259Sdelphijudp6_ctlinput(int cmd, struct sockaddr *sa, void *d) 48554263Sshin{ 48654263Sshin struct udphdr uh; 48754263Sshin struct ip6_hdr *ip6; 48854263Sshin struct mbuf *m; 48962587Sitojun int off = 0; 49078064Sume struct ip6ctlparam *ip6cp = NULL; 49178064Sume const struct sockaddr_in6 *sa6_src = NULL; 492125776Sume void *cmdarg; 493175162Sobrien struct inpcb *(*notify)(struct inpcb *, int) = udp_notify; 49478064Sume struct udp_portonly { 49578064Sume u_int16_t uh_sport; 49678064Sume u_int16_t uh_dport; 49778064Sume } *uhp; 49854263Sshin 49954263Sshin if (sa->sa_family != AF_INET6 || 50054263Sshin sa->sa_len != sizeof(struct sockaddr_in6)) 50154263Sshin return; 50254263Sshin 50362587Sitojun if ((unsigned)cmd >= PRC_NCMDS) 50454263Sshin return; 50562587Sitojun if (PRC_IS_REDIRECT(cmd)) 50662587Sitojun notify = in6_rtchange, d = NULL; 50762587Sitojun else if (cmd == PRC_HOSTDEAD) 50862587Sitojun d = NULL; 50962587Sitojun else if (inet6ctlerrmap[cmd] == 0) 51062587Sitojun return; 51154263Sshin 51254263Sshin /* if the parameter is from icmp6, decode it. */ 51354263Sshin if (d != NULL) { 51478064Sume ip6cp = (struct ip6ctlparam *)d; 51554263Sshin m = ip6cp->ip6c_m; 51654263Sshin ip6 = ip6cp->ip6c_ip6; 51754263Sshin off = ip6cp->ip6c_off; 518125776Sume cmdarg = ip6cp->ip6c_cmdarg; 51978064Sume sa6_src = ip6cp->ip6c_src; 52054263Sshin } else { 52154263Sshin m = NULL; 52254263Sshin ip6 = NULL; 523125776Sume cmdarg = NULL; 52478064Sume sa6_src = &sa6_any; 52554263Sshin } 52654263Sshin 52754263Sshin if (ip6) { 52854263Sshin /* 52954263Sshin * XXX: We assume that when IPV6 is non NULL, 53054263Sshin * M and OFF are valid. 53154263Sshin */ 53254263Sshin 533171328Srwatson /* Check if we can safely examine src and dst ports. */ 53478064Sume if (m->m_pkthdr.len < off + sizeof(*uhp)) 53567456Sitojun return; 53667456Sitojun 53778064Sume bzero(&uh, sizeof(uh)); 53878064Sume m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 53978064Sume 540181803Sbz (void) in6_pcbnotify(&V_udbinfo, sa, uh.uh_dport, 541171328Srwatson (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd, 542171328Srwatson cmdarg, notify); 54354263Sshin } else 544181803Sbz (void) in6_pcbnotify(&V_udbinfo, sa, 0, 545171328Srwatson (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify); 54654263Sshin} 54754263Sshin 54854263Sshinstatic int 54962573Sphkudp6_getcred(SYSCTL_HANDLER_ARGS) 55054263Sshin{ 55172650Sgreen struct xucred xuc; 55254263Sshin struct sockaddr_in6 addrs[2]; 55354263Sshin struct inpcb *inp; 554157674Srwatson int error; 55554263Sshin 556170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 55754263Sshin if (error) 55854263Sshin return (error); 55962587Sitojun 56062587Sitojun if (req->newlen != sizeof(addrs)) 56162587Sitojun return (EINVAL); 56272650Sgreen if (req->oldlen != sizeof(struct xucred)) 56362587Sitojun return (EINVAL); 56454263Sshin error = SYSCTL_IN(req, addrs, sizeof(addrs)); 56554263Sshin if (error) 56654263Sshin return (error); 567181803Sbz if ((error = sa6_embedscope(&addrs[0], V_ip6_use_defzone)) != 0 || 568181803Sbz (error = sa6_embedscope(&addrs[1], V_ip6_use_defzone)) != 0) { 569148385Sume return (error); 570148385Sume } 571222488Srwatson inp = in6_pcblookup(&V_udbinfo, &addrs[1].sin6_addr, 572222488Srwatson addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 573222488Srwatson INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); 574179412Srwatson if (inp != NULL) { 575222488Srwatson INP_RLOCK_ASSERT(inp); 576179412Srwatson if (inp->inp_socket == NULL) 577179412Srwatson error = ENOENT; 578179412Srwatson if (error == 0) 579179412Srwatson error = cr_canseesocket(req->td->td_ucred, 580179412Srwatson inp->inp_socket); 581179412Srwatson if (error == 0) 582183606Sbz cru2x(inp->inp_cred, &xuc); 583179412Srwatson INP_RUNLOCK(inp); 584222488Srwatson } else 585171609Srwatson error = ENOENT; 586171609Srwatson if (error == 0) 587171609Srwatson error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 58854263Sshin return (error); 58954263Sshin} 59054263Sshin 591171328SrwatsonSYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 592171328Srwatson 0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); 59354263Sshin 594171552Srwatsonstatic int 595172087Srwatsonudp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, 596171552Srwatson struct mbuf *control, struct thread *td) 597171552Srwatson{ 598171552Srwatson u_int32_t ulen = m->m_pkthdr.len; 599171552Srwatson u_int32_t plen = sizeof(struct udphdr) + ulen; 600171552Srwatson struct ip6_hdr *ip6; 601171552Srwatson struct udphdr *udp6; 602194777Sbz struct in6_addr *laddr, *faddr, in6a; 603171552Srwatson struct sockaddr_in6 *sin6 = NULL; 604171552Srwatson struct ifnet *oifp = NULL; 605171552Srwatson int scope_ambiguous = 0; 606171552Srwatson u_short fport; 607171552Srwatson int error = 0; 608171552Srwatson struct ip6_pktopts *optp, opt; 609171552Srwatson int af = AF_INET6, hlen = sizeof(struct ip6_hdr); 610171552Srwatson int flags; 611171552Srwatson struct sockaddr_in6 tmp; 612171552Srwatson 613178285Srwatson INP_WLOCK_ASSERT(inp); 614222488Srwatson INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); 615171552Srwatson 616171552Srwatson if (addr6) { 617171552Srwatson /* addr6 has been validated in udp6_send(). */ 618171552Srwatson sin6 = (struct sockaddr_in6 *)addr6; 619171552Srwatson 620171552Srwatson /* protect *sin6 from overwrites */ 621171552Srwatson tmp = *sin6; 622171552Srwatson sin6 = &tmp; 623171552Srwatson 624171552Srwatson /* 625171552Srwatson * Application should provide a proper zone ID or the use of 626171552Srwatson * default zone IDs should be enabled. Unfortunately, some 627171552Srwatson * applications do not behave as it should, so we need a 628171552Srwatson * workaround. Even if an appropriate ID is not determined, 629171552Srwatson * we'll see if we can determine the outgoing interface. If we 630171552Srwatson * can, determine the zone ID based on the interface below. 631171552Srwatson */ 632181803Sbz if (sin6->sin6_scope_id == 0 && !V_ip6_use_defzone) 633171552Srwatson scope_ambiguous = 1; 634181803Sbz if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) 635171552Srwatson return (error); 636171552Srwatson } 637171552Srwatson 638171552Srwatson if (control) { 639171552Srwatson if ((error = ip6_setpktopts(control, &opt, 640175630Sbz inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0) 641171552Srwatson goto release; 642171552Srwatson optp = &opt; 643171552Srwatson } else 644172087Srwatson optp = inp->in6p_outputopts; 645171552Srwatson 646171552Srwatson if (sin6) { 647171552Srwatson faddr = &sin6->sin6_addr; 648171552Srwatson 649171552Srwatson /* 650171552Srwatson * Since we saw no essential reason for calling in_pcbconnect, 651171552Srwatson * we get rid of such kind of logic, and call in6_selectsrc 652171552Srwatson * and in6_pcbsetport in order to fill in the local address 653171552Srwatson * and the local port. 654171552Srwatson */ 655171552Srwatson if (sin6->sin6_port == 0) { 656171552Srwatson error = EADDRNOTAVAIL; 657171552Srwatson goto release; 658171552Srwatson } 659171552Srwatson 660172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 661171552Srwatson /* how about ::ffff:0.0.0.0 case? */ 662171552Srwatson error = EISCONN; 663171552Srwatson goto release; 664171552Srwatson } 665171552Srwatson 666171552Srwatson fport = sin6->sin6_port; /* allow 0 port */ 667171552Srwatson 668171552Srwatson if (IN6_IS_ADDR_V4MAPPED(faddr)) { 669186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 670171552Srwatson /* 671171552Srwatson * I believe we should explicitly discard the 672171552Srwatson * packet when mapped addresses are disabled, 673171552Srwatson * rather than send the packet as an IPv6 one. 674171552Srwatson * If we chose the latter approach, the packet 675171552Srwatson * might be sent out on the wire based on the 676171552Srwatson * default route, the situation which we'd 677171552Srwatson * probably want to avoid. 678171552Srwatson * (20010421 jinmei@kame.net) 679171552Srwatson */ 680171552Srwatson error = EINVAL; 681171552Srwatson goto release; 682171552Srwatson } 683172087Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && 684172087Srwatson !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) { 685171552Srwatson /* 686171552Srwatson * when remote addr is an IPv4-mapped address, 687171552Srwatson * local addr should not be an IPv6 address, 688171552Srwatson * since you cannot determine how to map IPv6 689171552Srwatson * source address to IPv4. 690171552Srwatson */ 691171552Srwatson error = EINVAL; 692171552Srwatson goto release; 693171552Srwatson } 694171552Srwatson 695171552Srwatson af = AF_INET; 696171552Srwatson } 697171552Srwatson 698171552Srwatson if (!IN6_IS_ADDR_V4MAPPED(faddr)) { 699194777Sbz error = in6_selectsrc(sin6, optp, inp, NULL, 700194777Sbz td->td_ucred, &oifp, &in6a); 701194777Sbz if (error) 702194777Sbz goto release; 703171552Srwatson if (oifp && scope_ambiguous && 704171552Srwatson (error = in6_setscope(&sin6->sin6_addr, 705171552Srwatson oifp, NULL))) { 706171552Srwatson goto release; 707171552Srwatson } 708194777Sbz laddr = &in6a; 709171552Srwatson } else 710172087Srwatson laddr = &inp->in6p_laddr; /* XXX */ 711171552Srwatson if (laddr == NULL) { 712171552Srwatson if (error == 0) 713171552Srwatson error = EADDRNOTAVAIL; 714171552Srwatson goto release; 715171552Srwatson } 716186141Sbz if (inp->inp_lport == 0 && 717219570Sbz (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) { 718219570Sbz /* Undo an address bind that may have occurred. */ 719219570Sbz inp->in6p_laddr = in6addr_any; 720171552Srwatson goto release; 721219570Sbz } 722171552Srwatson } else { 723172087Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 724171552Srwatson error = ENOTCONN; 725171552Srwatson goto release; 726171552Srwatson } 727172087Srwatson if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { 728186141Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 729171552Srwatson /* 730171552Srwatson * XXX: this case would happen when the 731171552Srwatson * application sets the V6ONLY flag after 732171552Srwatson * connecting the foreign address. 733171552Srwatson * Such applications should be fixed, 734171552Srwatson * so we bark here. 735171552Srwatson */ 736171552Srwatson log(LOG_INFO, "udp6_output: IPV6_V6ONLY " 737171552Srwatson "option was set for a connected socket\n"); 738171552Srwatson error = EINVAL; 739171552Srwatson goto release; 740171552Srwatson } else 741171552Srwatson af = AF_INET; 742171552Srwatson } 743172087Srwatson laddr = &inp->in6p_laddr; 744172087Srwatson faddr = &inp->in6p_faddr; 745186141Sbz fport = inp->inp_fport; 746171552Srwatson } 747171552Srwatson 748171552Srwatson if (af == AF_INET) 749171552Srwatson hlen = sizeof(struct ip); 750171552Srwatson 751171552Srwatson /* 752171552Srwatson * Calculate data length and get a mbuf 753171552Srwatson * for UDP and IP6 headers. 754171552Srwatson */ 755243882Sglebius M_PREPEND(m, hlen + sizeof(struct udphdr), M_NOWAIT); 756171552Srwatson if (m == 0) { 757171552Srwatson error = ENOBUFS; 758171552Srwatson goto release; 759171552Srwatson } 760171552Srwatson 761171552Srwatson /* 762171552Srwatson * Stuff checksum and output datagram. 763171552Srwatson */ 764171552Srwatson udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); 765186141Sbz udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ 766171552Srwatson udp6->uh_dport = fport; 767171552Srwatson if (plen <= 0xffff) 768171552Srwatson udp6->uh_ulen = htons((u_short)plen); 769171552Srwatson else 770171552Srwatson udp6->uh_ulen = 0; 771171552Srwatson udp6->uh_sum = 0; 772171552Srwatson 773171552Srwatson switch (af) { 774171552Srwatson case AF_INET6: 775171552Srwatson ip6 = mtod(m, struct ip6_hdr *); 776186141Sbz ip6->ip6_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; 777171552Srwatson ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 778171552Srwatson ip6->ip6_vfc |= IPV6_VERSION; 779171552Srwatson ip6->ip6_plen = htons((u_short)plen); 780171552Srwatson ip6->ip6_nxt = IPPROTO_UDP; 781172087Srwatson ip6->ip6_hlim = in6_selecthlim(inp, NULL); 782171552Srwatson ip6->ip6_src = *laddr; 783171552Srwatson ip6->ip6_dst = *faddr; 784171552Srwatson 785235959Sbz udp6->uh_sum = in6_cksum_pseudo(ip6, plen, IPPROTO_UDP, 0); 786236170Sbz m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; 787235959Sbz m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); 788171552Srwatson 789171552Srwatson flags = 0; 790171552Srwatson 791254889Smarkj UDP_PROBE(send, NULL, inp, ip6, inp, udp6); 792190963Srwatson UDPSTAT_INC(udps_opackets); 793172087Srwatson error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions, 794172087Srwatson NULL, inp); 795171552Srwatson break; 796171552Srwatson case AF_INET: 797171552Srwatson error = EAFNOSUPPORT; 798171552Srwatson goto release; 799171552Srwatson } 800171552Srwatson goto releaseopt; 801171552Srwatson 802171552Srwatsonrelease: 803171552Srwatson m_freem(m); 804171552Srwatson 805171552Srwatsonreleaseopt: 806171552Srwatson if (control) { 807171552Srwatson ip6_clearpktopts(&opt, -1); 808171552Srwatson m_freem(control); 809171552Srwatson } 810171552Srwatson return (error); 811171552Srwatson} 812171552Srwatson 813157366Srwatsonstatic void 81454263Sshinudp6_abort(struct socket *so) 81554263Sshin{ 81654263Sshin struct inpcb *inp; 81754263Sshin 818157374Srwatson inp = sotoinpcb(so); 819157374Srwatson KASSERT(inp != NULL, ("udp6_abort: inp == NULL")); 820157674Srwatson 821160549Srwatson#ifdef INET 822160549Srwatson if (inp->inp_vflag & INP_IPV4) { 823160549Srwatson struct pr_usrreqs *pru; 824160549Srwatson 825160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 826160549Srwatson (*pru->pru_abort)(so); 827160549Srwatson return; 828160549Srwatson } 829160549Srwatson#endif 830160549Srwatson 831178285Srwatson INP_WLOCK(inp); 832160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 833222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 834160549Srwatson in6_pcbdisconnect(inp); 835160549Srwatson inp->in6p_laddr = in6addr_any; 836222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 837160549Srwatson soisdisconnected(so); 838160549Srwatson } 839178285Srwatson INP_WUNLOCK(inp); 84054263Sshin} 84154263Sshin 84254263Sshinstatic int 84383366Sjulianudp6_attach(struct socket *so, int proto, struct thread *td) 84454263Sshin{ 84554263Sshin struct inpcb *inp; 846157674Srwatson int error; 84754263Sshin 84854263Sshin inp = sotoinpcb(so); 849157607Srwatson KASSERT(inp == NULL, ("udp6_attach: inp != NULL")); 850157674Srwatson 85154263Sshin if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 85254263Sshin error = soreserve(so, udp_sendspace, udp_recvspace); 853157374Srwatson if (error) 854171328Srwatson return (error); 85554263Sshin } 856181803Sbz INP_INFO_WLOCK(&V_udbinfo); 857181803Sbz error = in_pcballoc(so, &V_udbinfo); 858132714Srwatson if (error) { 859181803Sbz INP_INFO_WUNLOCK(&V_udbinfo); 860171328Srwatson return (error); 861132714Srwatson } 86254263Sshin inp = (struct inpcb *)so->so_pcb; 86354263Sshin inp->inp_vflag |= INP_IPV6; 864155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) 865100132Sume inp->inp_vflag |= INP_IPV4; 86654263Sshin inp->in6p_hops = -1; /* use kernel default */ 86754263Sshin inp->in6p_cksum = -1; /* just to be sure */ 86861958Sitojun /* 86961958Sitojun * XXX: ugly!! 87061958Sitojun * IPv4 TTL initialization is necessary for an IPv6 socket as well, 87161958Sitojun * because the socket may be bound to an IPv6 wildcard address, 87261958Sitojun * which may match an IPv4-mapped IPv6 address. 87361958Sitojun */ 874181803Sbz inp->inp_ip_ttl = V_ip_defttl; 875192649Sbz 876192649Sbz error = udp_newudpcb(inp); 877192649Sbz if (error) { 878192649Sbz in_pcbdetach(inp); 879192649Sbz in_pcbfree(inp); 880192649Sbz INP_INFO_WUNLOCK(&V_udbinfo); 881192649Sbz return (error); 882192649Sbz } 883178285Srwatson INP_WUNLOCK(inp); 884192649Sbz INP_INFO_WUNLOCK(&V_udbinfo); 885171328Srwatson return (0); 88654263Sshin} 88754263Sshin 88854263Sshinstatic int 88983366Sjulianudp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 89054263Sshin{ 89154263Sshin struct inpcb *inp; 892157674Srwatson int error; 89354263Sshin 894157374Srwatson inp = sotoinpcb(so); 895157374Srwatson KASSERT(inp != NULL, ("udp6_bind: inp == NULL")); 896157674Srwatson 897178285Srwatson INP_WLOCK(inp); 898222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 89954263Sshin inp->inp_vflag &= ~INP_IPV4; 90054263Sshin inp->inp_vflag |= INP_IPV6; 90178064Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 90254263Sshin struct sockaddr_in6 *sin6_p; 90354263Sshin 90454263Sshin sin6_p = (struct sockaddr_in6 *)nam; 90554263Sshin 90654263Sshin if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 90754263Sshin inp->inp_vflag |= INP_IPV4; 908221248Sbz#ifdef INET 90954263Sshin else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 91054263Sshin struct sockaddr_in sin; 91154263Sshin 91254263Sshin in6_sin6_2_sin(&sin, sin6_p); 91354263Sshin inp->inp_vflag |= INP_IPV4; 91454263Sshin inp->inp_vflag &= ~INP_IPV6; 915127505Spjd error = in_pcbbind(inp, (struct sockaddr *)&sin, 916127505Spjd td->td_ucred); 917132714Srwatson goto out; 91854263Sshin } 919221248Sbz#endif 92054263Sshin } 92154263Sshin 922127505Spjd error = in6_pcbbind(inp, nam, td->td_ucred); 923221248Sbz#ifdef INET 924132714Srwatsonout: 925221248Sbz#endif 926222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 927178285Srwatson INP_WUNLOCK(inp); 928171328Srwatson return (error); 92954263Sshin} 93054263Sshin 931160549Srwatsonstatic void 932160549Srwatsonudp6_close(struct socket *so) 933160549Srwatson{ 934160549Srwatson struct inpcb *inp; 935160549Srwatson 936160549Srwatson inp = sotoinpcb(so); 937160549Srwatson KASSERT(inp != NULL, ("udp6_close: inp == NULL")); 938160549Srwatson 939160549Srwatson#ifdef INET 940160549Srwatson if (inp->inp_vflag & INP_IPV4) { 941160549Srwatson struct pr_usrreqs *pru; 942160549Srwatson 943160549Srwatson pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 944160549Srwatson (*pru->pru_disconnect)(so); 945160549Srwatson return; 946160549Srwatson } 947160549Srwatson#endif 948178285Srwatson INP_WLOCK(inp); 949160549Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 950222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 951160549Srwatson in6_pcbdisconnect(inp); 952160549Srwatson inp->in6p_laddr = in6addr_any; 953222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 954160549Srwatson soisdisconnected(so); 955160549Srwatson } 956178285Srwatson INP_WUNLOCK(inp); 957160549Srwatson} 958160549Srwatson 95954263Sshinstatic int 96083366Sjulianudp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 96154263Sshin{ 96254263Sshin struct inpcb *inp; 963188151Sjamie struct sockaddr_in6 *sin6; 964157674Srwatson int error; 96554263Sshin 966157374Srwatson inp = sotoinpcb(so); 967188151Sjamie sin6 = (struct sockaddr_in6 *)nam; 968157374Srwatson KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); 969157674Srwatson 970222488Srwatson /* 971222488Srwatson * XXXRW: Need to clarify locking of v4/v6 flags. 972222488Srwatson */ 973178285Srwatson INP_WLOCK(inp); 974221248Sbz#ifdef INET 975220462Sbz if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 976188151Sjamie struct sockaddr_in sin; 97754263Sshin 978220462Sbz if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { 979220462Sbz error = EINVAL; 980220462Sbz goto out; 981220462Sbz } 982188151Sjamie if (inp->inp_faddr.s_addr != INADDR_ANY) { 983188151Sjamie error = EISCONN; 984132714Srwatson goto out; 98554263Sshin } 986188151Sjamie in6_sin6_2_sin(&sin, sin6); 987220462Sbz inp->inp_vflag |= INP_IPV4; 988220462Sbz inp->inp_vflag &= ~INP_IPV6; 989188151Sjamie error = prison_remote_ip4(td->td_ucred, &sin.sin_addr); 990188151Sjamie if (error != 0) 991188151Sjamie goto out; 992222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 993188151Sjamie error = in_pcbconnect(inp, (struct sockaddr *)&sin, 994188151Sjamie td->td_ucred); 995222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 996220462Sbz if (error == 0) 997188151Sjamie soisconnected(so); 998188151Sjamie goto out; 99954263Sshin } 1000221248Sbz#endif 1001132714Srwatson if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1002132714Srwatson error = EISCONN; 1003132714Srwatson goto out; 1004132714Srwatson } 1005220462Sbz inp->inp_vflag &= ~INP_IPV4; 1006220462Sbz inp->inp_vflag |= INP_IPV6; 1007188151Sjamie error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); 1008188151Sjamie if (error != 0) 1009188151Sjamie goto out; 1010222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 1011127505Spjd error = in6_pcbconnect(inp, nam, td->td_ucred); 1012222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1013220462Sbz if (error == 0) 101454263Sshin soisconnected(so); 1015132714Srwatsonout: 1016178285Srwatson INP_WUNLOCK(inp); 1017171328Srwatson return (error); 101854263Sshin} 101954263Sshin 1020157370Srwatsonstatic void 102154263Sshinudp6_detach(struct socket *so) 102254263Sshin{ 102354263Sshin struct inpcb *inp; 1024192649Sbz struct udpcb *up; 102554263Sshin 1026157374Srwatson inp = sotoinpcb(so); 1027157374Srwatson KASSERT(inp != NULL, ("udp6_detach: inp == NULL")); 1028157674Srwatson 1029181803Sbz INP_INFO_WLOCK(&V_udbinfo); 1030178285Srwatson INP_WLOCK(inp); 1031192649Sbz up = intoudpcb(inp); 1032192649Sbz KASSERT(up != NULL, ("%s: up == NULL", __func__)); 1033185344Sbz in_pcbdetach(inp); 1034185370Sbz in_pcbfree(inp); 1035181803Sbz INP_INFO_WUNLOCK(&V_udbinfo); 1036192649Sbz udp_discardcb(up); 103754263Sshin} 103854263Sshin 103954263Sshinstatic int 104054263Sshinudp6_disconnect(struct socket *so) 104154263Sshin{ 104254263Sshin struct inpcb *inp; 1043157674Srwatson int error; 104454263Sshin 1045157374Srwatson inp = sotoinpcb(so); 1046157374Srwatson KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL")); 1047157674Srwatson 1048125777Sume#ifdef INET 104954263Sshin if (inp->inp_vflag & INP_IPV4) { 105054263Sshin struct pr_usrreqs *pru; 105154263Sshin 105254263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1053222488Srwatson (void)(*pru->pru_disconnect)(so); 1054222488Srwatson return (0); 105554263Sshin } 1056125777Sume#endif 105754263Sshin 1058222488Srwatson INP_WLOCK(inp); 1059222488Srwatson 1060132714Srwatson if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 1061132714Srwatson error = ENOTCONN; 1062132714Srwatson goto out; 1063132714Srwatson } 106454263Sshin 1065222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 106654263Sshin in6_pcbdisconnect(inp); 106754263Sshin inp->in6p_laddr = in6addr_any; 1068222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1069183807Srwatson SOCK_LOCK(so); 107054263Sshin so->so_state &= ~SS_ISCONNECTED; /* XXX */ 1071183807Srwatson SOCK_UNLOCK(so); 1072132714Srwatsonout: 1073178285Srwatson INP_WUNLOCK(inp); 1074171328Srwatson return (0); 107554263Sshin} 107654263Sshin 107754263Sshinstatic int 1078171328Srwatsonudp6_send(struct socket *so, int flags, struct mbuf *m, 1079171328Srwatson struct sockaddr *addr, struct mbuf *control, struct thread *td) 108054263Sshin{ 108154263Sshin struct inpcb *inp; 108262587Sitojun int error = 0; 108354263Sshin 1084157374Srwatson inp = sotoinpcb(so); 1085157374Srwatson KASSERT(inp != NULL, ("udp6_send: inp == NULL")); 1086157674Srwatson 1087178285Srwatson INP_WLOCK(inp); 108862587Sitojun if (addr) { 1089171260Sdelphij if (addr->sa_len != sizeof(struct sockaddr_in6)) { 109062587Sitojun error = EINVAL; 109162587Sitojun goto bad; 109262587Sitojun } 109362587Sitojun if (addr->sa_family != AF_INET6) { 109462587Sitojun error = EAFNOSUPPORT; 109562587Sitojun goto bad; 109662587Sitojun } 109762587Sitojun } 109862587Sitojun 1099125777Sume#ifdef INET 1100155217Sume if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 110154263Sshin int hasv4addr; 110254263Sshin struct sockaddr_in6 *sin6 = 0; 110354263Sshin 110454263Sshin if (addr == 0) 110554263Sshin hasv4addr = (inp->inp_vflag & INP_IPV4); 110654263Sshin else { 110754263Sshin sin6 = (struct sockaddr_in6 *)addr; 110854263Sshin hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) 1109171328Srwatson ? 1 : 0; 111054263Sshin } 111154263Sshin if (hasv4addr) { 111254263Sshin struct pr_usrreqs *pru; 111354263Sshin 1114183265Srwatson /* 1115183265Srwatson * XXXRW: We release UDP-layer locks before calling 1116183265Srwatson * udp_send() in order to avoid recursion. However, 1117183265Srwatson * this does mean there is a short window where inp's 1118183265Srwatson * fields are unstable. Could this lead to a 1119183265Srwatson * potential race in which the factors causing us to 1120183265Srwatson * select the UDPv4 output routine are invalidated? 1121183265Srwatson */ 1122183265Srwatson INP_WUNLOCK(inp); 112354263Sshin if (sin6) 112454263Sshin in6_sin6_2_sin_in_sock(addr); 112554263Sshin pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 1126183265Srwatson /* addr will just be freed in sendit(). */ 1127183265Srwatson return ((*pru->pru_send)(so, flags, m, addr, control, 1128171328Srwatson td)); 112954263Sshin } 113054263Sshin } 1131125777Sume#endif 1132171508Srwatson#ifdef MAC 1133172930Srwatson mac_inpcb_create_mbuf(inp, m); 1134171508Srwatson#endif 1135222488Srwatson INP_HASH_WLOCK(&V_udbinfo); 1136132714Srwatson error = udp6_output(inp, m, addr, control, td); 1137222488Srwatson INP_HASH_WUNLOCK(&V_udbinfo); 1138207828Skmacy#ifdef INET 1139207828Skmacy#endif 1140178285Srwatson INP_WUNLOCK(inp); 1141171328Srwatson return (error); 114262587Sitojun 1143171328Srwatsonbad: 1144178285Srwatson INP_WUNLOCK(inp); 114562587Sitojun m_freem(m); 1146120856Sume return (error); 114754263Sshin} 114854263Sshin 114954263Sshinstruct pr_usrreqs udp6_usrreqs = { 1150137386Sphk .pru_abort = udp6_abort, 1151137386Sphk .pru_attach = udp6_attach, 1152137386Sphk .pru_bind = udp6_bind, 1153137386Sphk .pru_connect = udp6_connect, 1154137386Sphk .pru_control = in6_control, 1155137386Sphk .pru_detach = udp6_detach, 1156137386Sphk .pru_disconnect = udp6_disconnect, 1157137386Sphk .pru_peeraddr = in6_mapped_peeraddr, 1158137386Sphk .pru_send = udp6_send, 1159137386Sphk .pru_shutdown = udp_shutdown, 1160137386Sphk .pru_sockaddr = in6_mapped_sockaddr, 1161180365Srwatson .pru_soreceive = soreceive_dgram, 1162180365Srwatson .pru_sosend = sosend_dgram, 1163160549Srwatson .pru_sosetlabel = in_pcbsosetlabel, 1164160549Srwatson .pru_close = udp6_close 116554263Sshin}; 1166