udp6_usrreq.c revision 125941
1168404Spjd/* $FreeBSD: head/sys/netinet6/udp6_usrreq.c 125941 2004-02-17 14:02:37Z ume $ */ 2168404Spjd/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ 3168404Spjd 4168404Spjd/* 5168404Spjd * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6168404Spjd * All rights reserved. 7168404Spjd * 8168404Spjd * Redistribution and use in source and binary forms, with or without 9168404Spjd * modification, are permitted provided that the following conditions 10168404Spjd * are met: 11168404Spjd * 1. Redistributions of source code must retain the above copyright 12168404Spjd * notice, this list of conditions and the following disclaimer. 13168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 14168404Spjd * notice, this list of conditions and the following disclaimer in the 15168404Spjd * documentation and/or other materials provided with the distribution. 16168404Spjd * 3. Neither the name of the project nor the names of its contributors 17168404Spjd * may be used to endorse or promote products derived from this software 18168404Spjd * without specific prior written permission. 19168404Spjd * 20168404Spjd * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22208050Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28213197Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30168404Spjd * SUCH DAMAGE. 31168404Spjd */ 32168404Spjd 33168404Spjd/* 34168404Spjd * Copyright (c) 1982, 1986, 1989, 1993 35168404Spjd * The Regents of the University of California. All rights reserved. 36168404Spjd * 37168404Spjd * Redistribution and use in source and binary forms, with or without 38168404Spjd * modification, are permitted provided that the following conditions 39168404Spjd * are met: 40168404Spjd * 1. Redistributions of source code must retain the above copyright 41168404Spjd * notice, this list of conditions and the following disclaimer. 42168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 43168404Spjd * notice, this list of conditions and the following disclaimer in the 44168404Spjd * documentation and/or other materials provided with the distribution. 45168404Spjd * 3. All advertising materials mentioning features or use of this software 46168404Spjd * must display the following acknowledgement: 47168404Spjd * This product includes software developed by the University of 48168404Spjd * California, Berkeley and its contributors. 49168404Spjd * 4. Neither the name of the University nor the names of its contributors 50168404Spjd * may be used to endorse or promote products derived from this software 51168404Spjd * without specific prior written permission. 52168404Spjd * 53168404Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63168404Spjd * SUCH DAMAGE. 64168404Spjd * 65168404Spjd * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 66168404Spjd */ 67168404Spjd 68168404Spjd#include "opt_inet.h" 69168404Spjd#include "opt_inet6.h" 70168404Spjd#include "opt_ipsec.h" 71168404Spjd 72169028Spjd#include <sys/param.h> 73168404Spjd#include <sys/errno.h> 74168404Spjd#include <sys/kernel.h> 75168404Spjd#include <sys/lock.h> 76168404Spjd#include <sys/mbuf.h> 77168404Spjd#include <sys/proc.h> 78168404Spjd#include <sys/protosw.h> 79168404Spjd#include <sys/signalvar.h> 80168404Spjd#include <sys/socket.h> 81168404Spjd#include <sys/socketvar.h> 82168404Spjd#include <sys/stat.h> 83168404Spjd#include <sys/sx.h> 84168404Spjd#include <sys/sysctl.h> 85168404Spjd#include <sys/syslog.h> 86168404Spjd#include <sys/systm.h> 87168404Spjd 88168404Spjd#include <net/if.h> 89168404Spjd#include <net/if_types.h> 90168404Spjd#include <net/route.h> 91168404Spjd 92168404Spjd#include <netinet/in.h> 93168404Spjd#include <netinet/in_pcb.h> 94168404Spjd#include <netinet/in_systm.h> 95168404Spjd#include <netinet/in_var.h> 96168404Spjd#include <netinet/ip.h> 97168404Spjd#include <netinet/ip6.h> 98168404Spjd#include <netinet/icmp6.h> 99168404Spjd#include <netinet/ip_var.h> 100168404Spjd#include <netinet/udp.h> 101168404Spjd#include <netinet/udp_var.h> 102168404Spjd#include <netinet6/ip6protosw.h> 103168404Spjd#include <netinet6/ip6_var.h> 104168404Spjd#include <netinet6/in6_pcb.h> 105168404Spjd#include <netinet6/udp6_var.h> 106168404Spjd 107168404Spjd#ifdef IPSEC 108168404Spjd#include <netinet6/ipsec.h> 109168404Spjd#include <netinet6/ipsec6.h> 110168404Spjd#endif /* IPSEC */ 111168404Spjd 112168404Spjd#ifdef FAST_IPSEC 113168404Spjd#include <netipsec/ipsec.h> 114168404Spjd#include <netipsec/ipsec6.h> 115168404Spjd#endif /* FAST_IPSEC */ 116168404Spjd 117168404Spjd/* 118168404Spjd * UDP protocol inplementation. 119168404Spjd * Per RFC 768, August, 1980. 120168404Spjd */ 121168404Spjd 122168404Spjdextern struct protosw inetsw[]; 123168404Spjdstatic int udp6_detach __P((struct socket *so)); 124168404Spjd 125168404Spjdint 126168404Spjdudp6_input(mp, offp, proto) 127168404Spjd struct mbuf **mp; 128168404Spjd int *offp, proto; 129168404Spjd{ 130168404Spjd struct mbuf *m = *mp, *opts; 131168404Spjd register struct ip6_hdr *ip6; 132168404Spjd register struct udphdr *uh; 133168404Spjd register struct inpcb *in6p; 134168404Spjd int off = *offp; 135168404Spjd int plen, ulen; 136168404Spjd struct sockaddr_in6 fromsa; 137168404Spjd 138168404Spjd opts = NULL; 139168404Spjd 140168404Spjd ip6 = mtod(m, struct ip6_hdr *); 141168404Spjd 142168404Spjd if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 143168404Spjd /* XXX send icmp6 host/port unreach? */ 144168404Spjd m_freem(m); 145168404Spjd return IPPROTO_DONE; 146168404Spjd } 147168404Spjd 148168404Spjd#ifndef PULLDOWN_TEST 149168404Spjd IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 150168404Spjd ip6 = mtod(m, struct ip6_hdr *); 151168404Spjd uh = (struct udphdr *)((caddr_t)ip6 + off); 152168404Spjd#else 153168404Spjd IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh)); 154168404Spjd if (!uh) 155168404Spjd return IPPROTO_DONE; 156168404Spjd#endif 157168404Spjd 158168404Spjd udpstat.udps_ipackets++; 159168404Spjd 160168404Spjd plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 161168404Spjd ulen = ntohs((u_short)uh->uh_ulen); 162168404Spjd 163168404Spjd if (plen != ulen) { 164168404Spjd udpstat.udps_badlen++; 165168404Spjd goto bad; 166168404Spjd } 167168404Spjd 168168404Spjd /* 169168404Spjd * Checksum extended UDP header and data. 170168404Spjd */ 171168404Spjd if (uh->uh_sum == 0) 172168404Spjd udpstat.udps_nosum++; 173168404Spjd else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { 174168404Spjd udpstat.udps_badsum++; 175168404Spjd goto bad; 176185029Spjd } 177185029Spjd 178185029Spjd if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 179185029Spjd struct inpcb *last; 180185029Spjd 181168404Spjd /* 182168404Spjd * Deliver a multicast datagram to all sockets 183168404Spjd * for which the local and remote addresses and ports match 184168404Spjd * those of the incoming datagram. This allows more than 185168404Spjd * one process to receive multicasts on the same port. 186168404Spjd * (This really ought to be done for unicast datagrams as 187168404Spjd * well, but that would cause problems with existing 188168404Spjd * applications that open both address-specific sockets and 189168404Spjd * a wildcard socket listening to the same port -- they would 190168404Spjd * end up receiving duplicates of every unicast datagram. 191185029Spjd * Those applications open the multiple sockets to overcome an 192185029Spjd * inadequacy of the UDP socket interface, but for backwards 193168404Spjd * compatibility we avoid the problem here rather than 194168404Spjd * fixing the interface. Maybe 4.5BSD will remedy this?) 195185029Spjd */ 196185029Spjd 197168404Spjd /* 198168404Spjd * In a case that laddr should be set to the link-local 199168404Spjd * address (this happens in RIPng), the multicast address 200185029Spjd * specified in the received packet does not match with 201185029Spjd * laddr. To cure this situation, the matching is relaxed 202185029Spjd * if the receiving interface is the same as one specified 203185029Spjd * in the socket and if the destination multicast address 204185029Spjd * matches one of the multicast groups specified in the socket. 205168404Spjd */ 206168404Spjd 207168404Spjd /* 208168404Spjd * Construct sockaddr format source address. 209168404Spjd */ 210168404Spjd init_sin6(&fromsa, m); 211168404Spjd fromsa.sin6_port = uh->uh_sport; 212168404Spjd /* 213168404Spjd * KAME note: traditionally we dropped udpiphdr from mbuf here. 214168404Spjd * We need udphdr for IPsec processing so we do that later. 215168404Spjd */ 216168404Spjd 217168404Spjd /* 218168404Spjd * Locate pcb(s) for datagram. 219168404Spjd * (Algorithm copied from raw_intr().) 220168404Spjd */ 221168404Spjd last = NULL; 222168404Spjd LIST_FOREACH(in6p, &udb, inp_list) { 223168404Spjd if ((in6p->inp_vflag & INP_IPV6) == 0) 224168404Spjd continue; 225168404Spjd if (in6p->in6p_lport != uh->uh_dport) 226168404Spjd continue; 227168404Spjd if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { 228168404Spjd if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, 229168404Spjd &ip6->ip6_dst)) 230168404Spjd continue; 231168404Spjd } 232168404Spjd if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 233168404Spjd if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, 234168404Spjd &ip6->ip6_src) || 235168404Spjd in6p->in6p_fport != uh->uh_sport) 236168404Spjd continue; 237168404Spjd } 238168404Spjd 239168404Spjd if (last != NULL) { 240168404Spjd struct mbuf *n; 241168404Spjd 242168404Spjd#if defined(IPSEC) || defined(FAST_IPSEC) 243168404Spjd /* 244168404Spjd * Check AH/ESP integrity. 245168404Spjd */ 246168404Spjd if (ipsec6_in_reject(m, last)) { 247168404Spjd#ifdef IPSEC 248168404Spjd ipsec6stat.in_polvio++; 249168404Spjd#endif /* IPSEC */ 250168404Spjd /* do not inject data into pcb */ 251168404Spjd } else 252168404Spjd#endif /*IPSEC || FAST_IPSEC*/ 253168404Spjd if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 254168404Spjd /* 255168404Spjd * KAME NOTE: do not 256168404Spjd * m_copy(m, offset, ...) above. 257168404Spjd * sbappendaddr() expects M_PKTHDR, 258168404Spjd * and m_copy() will copy M_PKTHDR 259168404Spjd * only if offset is 0. 260168404Spjd */ 261168404Spjd if (last->in6p_flags & IN6P_CONTROLOPTS 262168404Spjd || last->in6p_socket->so_options & SO_TIMESTAMP) 263168404Spjd ip6_savecontrol(last, n, &opts); 264168404Spjd 265168404Spjd m_adj(n, off + sizeof(struct udphdr)); 266168404Spjd if (sbappendaddr(&last->in6p_socket->so_rcv, 267168404Spjd (struct sockaddr *)&fromsa, 268168404Spjd n, opts) == 0) { 269168404Spjd m_freem(n); 270168404Spjd if (opts) 271168404Spjd m_freem(opts); 272168404Spjd udpstat.udps_fullsock++; 273168404Spjd } else 274168404Spjd sorwakeup(last->in6p_socket); 275168404Spjd opts = NULL; 276168404Spjd } 277168404Spjd } 278168404Spjd last = in6p; 279168404Spjd /* 280168404Spjd * Don't look for additional matches if this one does 281168404Spjd * not have either the SO_REUSEPORT or SO_REUSEADDR 282168404Spjd * socket options set. This heuristic avoids searching 283168404Spjd * through all pcbs in the common case of a non-shared 284168404Spjd * port. It assumes that an application will never 285168404Spjd * clear these options after setting them. 286168404Spjd */ 287168404Spjd if ((last->in6p_socket->so_options & 288168404Spjd (SO_REUSEPORT|SO_REUSEADDR)) == 0) 289168404Spjd break; 290168404Spjd } 291168404Spjd 292168404Spjd if (last == NULL) { 293168404Spjd /* 294168404Spjd * No matching pcb found; discard datagram. 295168404Spjd * (No need to send an ICMP Port Unreachable 296168404Spjd * for a broadcast or multicast datgram.) 297168404Spjd */ 298168404Spjd udpstat.udps_noport++; 299185029Spjd udpstat.udps_noportmcast++; 300185029Spjd goto bad; 301168404Spjd } 302168404Spjd#if defined(IPSEC) || defined(FAST_IPSEC) 303168404Spjd /* 304168404Spjd * Check AH/ESP integrity. 305168404Spjd */ 306168404Spjd if (ipsec6_in_reject(m, last)) { 307168404Spjd#ifdef IPSEC 308168404Spjd ipsec6stat.in_polvio++; 309168404Spjd#endif /* IPSEC */ 310168404Spjd goto bad; 311168404Spjd } 312168404Spjd#endif /*IPSEC || FAST_IPSEC*/ 313168404Spjd if (last->in6p_flags & IN6P_CONTROLOPTS 314168404Spjd || last->in6p_socket->so_options & SO_TIMESTAMP) 315168404Spjd ip6_savecontrol(last, m, &opts); 316168404Spjd 317168404Spjd m_adj(m, off + sizeof(struct udphdr)); 318168404Spjd if (sbappendaddr(&last->in6p_socket->so_rcv, 319168404Spjd (struct sockaddr *)&fromsa, 320168404Spjd m, opts) == 0) { 321168404Spjd udpstat.udps_fullsock++; 322168404Spjd goto bad; 323168404Spjd } 324168404Spjd sorwakeup(last->in6p_socket); 325168404Spjd return IPPROTO_DONE; 326168404Spjd } 327168404Spjd /* 328168404Spjd * Locate pcb for datagram. 329168404Spjd */ 330168404Spjd in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport, 331168404Spjd &ip6->ip6_dst, uh->uh_dport, 1, 332168404Spjd m->m_pkthdr.rcvif); 333168404Spjd if (in6p == 0) { 334168404Spjd if (log_in_vain) { 335168404Spjd char buf[INET6_ADDRSTRLEN]; 336168404Spjd 337168404Spjd strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); 338168404Spjd log(LOG_INFO, 339168404Spjd "Connection attempt to UDP [%s]:%d from [%s]:%d\n", 340168404Spjd buf, ntohs(uh->uh_dport), 341168404Spjd ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); 342168404Spjd } 343168404Spjd udpstat.udps_noport++; 344168404Spjd if (m->m_flags & M_MCAST) { 345168404Spjd printf("UDP6: M_MCAST is set in a unicast packet.\n"); 346168404Spjd udpstat.udps_noportmcast++; 347168404Spjd goto bad; 348168404Spjd } 349168404Spjd icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 350168404Spjd return IPPROTO_DONE; 351168404Spjd } 352168404Spjd#if defined(IPSEC) || defined(FAST_IPSEC) 353168404Spjd /* 354168404Spjd * Check AH/ESP integrity. 355168404Spjd */ 356168404Spjd if (ipsec6_in_reject(m, in6p)) { 357168404Spjd#ifdef IPSEC 358168404Spjd ipsec6stat.in_polvio++; 359168404Spjd#endif /* IPSEC */ 360168404Spjd goto bad; 361168404Spjd } 362207908Smm#endif /*IPSEC || FAST_IPSEC*/ 363207908Smm 364168404Spjd /* 365207908Smm * Construct sockaddr format source address. 366168404Spjd * Stuff source address and datagram in user buffer. 367168404Spjd */ 368168404Spjd init_sin6(&fromsa, m); 369168404Spjd fromsa.sin6_port = uh->uh_sport; 370168404Spjd if (in6p->in6p_flags & IN6P_CONTROLOPTS 371207908Smm || in6p->in6p_socket->so_options & SO_TIMESTAMP) 372207908Smm ip6_savecontrol(in6p, m, &opts); 373207908Smm m_adj(m, off + sizeof(struct udphdr)); 374207908Smm if (sbappendaddr(&in6p->in6p_socket->so_rcv, 375207908Smm (struct sockaddr *)&fromsa, m, opts) == 0) { 376168404Spjd udpstat.udps_fullsock++; 377168404Spjd goto bad; 378168404Spjd } 379168404Spjd sorwakeup(in6p->in6p_socket); 380168404Spjd return IPPROTO_DONE; 381168404Spjdbad: 382168404Spjd if (m) 383168404Spjd m_freem(m); 384168404Spjd if (opts) 385168404Spjd m_freem(opts); 386168404Spjd return IPPROTO_DONE; 387168404Spjd} 388168404Spjd 389168404Spjdvoid 390168404Spjdudp6_ctlinput(cmd, sa, d) 391168404Spjd int cmd; 392168404Spjd struct sockaddr *sa; 393168404Spjd void *d; 394168404Spjd{ 395168404Spjd struct udphdr uh; 396168404Spjd struct ip6_hdr *ip6; 397168404Spjd struct mbuf *m; 398168404Spjd int off = 0; 399168404Spjd struct ip6ctlparam *ip6cp = NULL; 400168404Spjd const struct sockaddr_in6 *sa6_src = NULL; 401168404Spjd void *cmdarg; 402168404Spjd struct inpcb *(*notify) __P((struct inpcb *, int)) = udp_notify; 403168404Spjd struct udp_portonly { 404168404Spjd u_int16_t uh_sport; 405168404Spjd u_int16_t uh_dport; 406168404Spjd } *uhp; 407168404Spjd 408168404Spjd if (sa->sa_family != AF_INET6 || 409168404Spjd sa->sa_len != sizeof(struct sockaddr_in6)) 410168404Spjd return; 411168404Spjd 412168404Spjd if ((unsigned)cmd >= PRC_NCMDS) 413168404Spjd return; 414168404Spjd if (PRC_IS_REDIRECT(cmd)) 415168404Spjd notify = in6_rtchange, d = NULL; 416168404Spjd else if (cmd == PRC_HOSTDEAD) 417168404Spjd d = NULL; 418168404Spjd else if (inet6ctlerrmap[cmd] == 0) 419168404Spjd return; 420168404Spjd 421168404Spjd /* if the parameter is from icmp6, decode it. */ 422168404Spjd if (d != NULL) { 423168404Spjd ip6cp = (struct ip6ctlparam *)d; 424168404Spjd m = ip6cp->ip6c_m; 425168404Spjd ip6 = ip6cp->ip6c_ip6; 426168404Spjd off = ip6cp->ip6c_off; 427168404Spjd cmdarg = ip6cp->ip6c_cmdarg; 428168404Spjd sa6_src = ip6cp->ip6c_src; 429168404Spjd } else { 430168404Spjd m = NULL; 431168404Spjd ip6 = NULL; 432168404Spjd cmdarg = NULL; 433168404Spjd sa6_src = &sa6_any; 434168404Spjd } 435168404Spjd 436168404Spjd if (ip6) { 437168404Spjd /* 438168404Spjd * XXX: We assume that when IPV6 is non NULL, 439168404Spjd * M and OFF are valid. 440168404Spjd */ 441168404Spjd 442168404Spjd /* check if we can safely examine src and dst ports */ 443168404Spjd if (m->m_pkthdr.len < off + sizeof(*uhp)) 444168404Spjd return; 445168404Spjd 446185029Spjd bzero(&uh, sizeof(uh)); 447185029Spjd m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 448185029Spjd 449185029Spjd (void) in6_pcbnotify(&udb, sa, uh.uh_dport, 450185029Spjd (struct sockaddr *)ip6cp->ip6c_src, 451185029Spjd uh.uh_sport, cmd, cmdarg, notify); 452185029Spjd } else 453185029Spjd (void) in6_pcbnotify(&udb, sa, 0, 454185029Spjd (const struct sockaddr *)sa6_src, 455185029Spjd 0, cmd, cmdarg, notify); 456168404Spjd} 457168404Spjd 458168404Spjdstatic int 459168404Spjdudp6_getcred(SYSCTL_HANDLER_ARGS) 460168404Spjd{ 461168404Spjd struct xucred xuc; 462168404Spjd struct sockaddr_in6 addrs[2]; 463168404Spjd struct inpcb *inp; 464168404Spjd int error, s; 465168404Spjd 466168404Spjd error = suser(req->td); 467168404Spjd if (error) 468168404Spjd return (error); 469168404Spjd 470168404Spjd if (req->newlen != sizeof(addrs)) 471168404Spjd return (EINVAL); 472168404Spjd if (req->oldlen != sizeof(struct xucred)) 473168404Spjd return (EINVAL); 474168404Spjd error = SYSCTL_IN(req, addrs, sizeof(addrs)); 475168404Spjd if (error) 476168404Spjd return (error); 477168404Spjd s = splnet(); 478168404Spjd inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr, 479185029Spjd addrs[1].sin6_port, 480168404Spjd &addrs[0].sin6_addr, addrs[0].sin6_port, 481185029Spjd 1, NULL); 482200724Sdelphij if (!inp || !inp->inp_socket) { 483200724Sdelphij error = ENOENT; 484200724Sdelphij goto out; 485200724Sdelphij } 486200724Sdelphij cru2x(inp->inp_socket->so_cred, &xuc); 487200724Sdelphij error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 488200724Sdelphijout: 489200724Sdelphij splx(s); 490200724Sdelphij return (error); 491200724Sdelphij} 492200724Sdelphij 493200724SdelphijSYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 494200724Sdelphij 0, 0, 495200724Sdelphij udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); 496200724Sdelphij 497200724Sdelphijstatic int 498200724Sdelphijudp6_abort(struct socket *so) 499200724Sdelphij{ 500168404Spjd struct inpcb *inp; 501168404Spjd int s; 502168404Spjd 503168404Spjd inp = sotoinpcb(so); 504168404Spjd if (inp == 0) 505168404Spjd return EINVAL; /* ??? possible? panic instead? */ 506168404Spjd soisdisconnected(so); 507168404Spjd s = splnet(); 508168404Spjd in6_pcbdetach(inp); 509168404Spjd splx(s); 510185029Spjd return 0; 511168404Spjd} 512185029Spjd 513168404Spjdstatic int 514168404Spjdudp6_attach(struct socket *so, int proto, struct thread *td) 515168404Spjd{ 516168404Spjd struct inpcb *inp; 517168404Spjd int s, error; 518168404Spjd 519213197Smm inp = sotoinpcb(so); 520213197Smm if (inp != 0) 521213197Smm return EINVAL; 522213197Smm 523213197Smm if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 524213197Smm error = soreserve(so, udp_sendspace, udp_recvspace); 525213197Smm if (error) 526168404Spjd return error; 527200724Sdelphij } 528200724Sdelphij s = splnet(); 529200724Sdelphij error = in_pcballoc(so, &udbinfo, td, "udp6inp"); 530200724Sdelphij splx(s); 531200724Sdelphij if (error) 532200724Sdelphij return error; 533200724Sdelphij inp = (struct inpcb *)so->so_pcb; 534200724Sdelphij inp->inp_vflag |= INP_IPV6; 535200724Sdelphij if (!ip6_v6only) 536200724Sdelphij inp->inp_vflag |= INP_IPV4; 537200724Sdelphij inp->in6p_hops = -1; /* use kernel default */ 538213197Smm inp->in6p_cksum = -1; /* just to be sure */ 539200724Sdelphij /* 540213197Smm * XXX: ugly!! 541213197Smm * IPv4 TTL initialization is necessary for an IPv6 socket as well, 542200724Sdelphij * because the socket may be bound to an IPv6 wildcard address, 543200724Sdelphij * which may match an IPv4-mapped IPv6 address. 544168404Spjd */ 545168404Spjd inp->inp_ip_ttl = ip_defttl; 546168404Spjd return 0; 547168404Spjd} 548168404Spjd 549168404Spjdstatic int 550168404Spjdudp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 551168404Spjd{ 552168404Spjd struct inpcb *inp; 553168404Spjd int s, error; 554168404Spjd 555168404Spjd inp = sotoinpcb(so); 556168404Spjd if (inp == 0) 557168404Spjd return EINVAL; 558168404Spjd 559168404Spjd inp->inp_vflag &= ~INP_IPV4; 560168404Spjd inp->inp_vflag |= INP_IPV6; 561168404Spjd if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 562168404Spjd struct sockaddr_in6 *sin6_p; 563185029Spjd 564185029Spjd sin6_p = (struct sockaddr_in6 *)nam; 565185029Spjd 566185029Spjd if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 567185029Spjd inp->inp_vflag |= INP_IPV4; 568185029Spjd else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 569185029Spjd struct sockaddr_in sin; 570185029Spjd 571168404Spjd in6_sin6_2_sin(&sin, sin6_p); 572185029Spjd inp->inp_vflag |= INP_IPV4; 573185029Spjd inp->inp_vflag &= ~INP_IPV6; 574185029Spjd s = splnet(); 575185029Spjd error = in_pcbbind(inp, (struct sockaddr *)&sin, td); 576185029Spjd splx(s); 577185029Spjd return error; 578185029Spjd } 579185029Spjd } 580168404Spjd 581185029Spjd s = splnet(); 582185029Spjd error = in6_pcbbind(inp, nam, td); 583185029Spjd splx(s); 584185029Spjd return error; 585185029Spjd} 586168404Spjd 587185029Spjdstatic int 588185029Spjdudp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 589185029Spjd{ 590185029Spjd struct inpcb *inp; 591185029Spjd int s, error; 592185029Spjd 593168404Spjd inp = sotoinpcb(so); 594185029Spjd if (inp == 0) 595185029Spjd return EINVAL; 596185029Spjd 597185029Spjd if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 598185029Spjd struct sockaddr_in6 *sin6_p; 599185029Spjd 600185029Spjd sin6_p = (struct sockaddr_in6 *)nam; 601185029Spjd if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 602185029Spjd struct sockaddr_in sin; 603185029Spjd 604185029Spjd if (inp->inp_faddr.s_addr != INADDR_ANY) 605185029Spjd return EISCONN; 606185029Spjd in6_sin6_2_sin(&sin, sin6_p); 607185029Spjd s = splnet(); 608168404Spjd error = in_pcbconnect(inp, (struct sockaddr *)&sin, td); 609168404Spjd splx(s); 610185029Spjd if (error == 0) { 611185029Spjd inp->inp_vflag |= INP_IPV4; 612185029Spjd inp->inp_vflag &= ~INP_IPV6; 613185029Spjd soisconnected(so); 614185029Spjd } 615185029Spjd return error; 616185029Spjd } 617185029Spjd } 618185029Spjd if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 619185029Spjd return EISCONN; 620185029Spjd s = splnet(); 621185029Spjd error = in6_pcbconnect(inp, nam, td); 622185029Spjd splx(s); 623185029Spjd if (error == 0) { 624168404Spjd if (!ip6_v6only) { /* should be non mapped addr */ 625185029Spjd inp->inp_vflag &= ~INP_IPV4; 626168404Spjd inp->inp_vflag |= INP_IPV6; 627185029Spjd } 628185029Spjd soisconnected(so); 629185029Spjd } 630185029Spjd return error; 631185029Spjd} 632168404Spjd 633185029Spjdstatic int 634185029Spjdudp6_detach(struct socket *so) 635168404Spjd{ 636185029Spjd struct inpcb *inp; 637168404Spjd int s; 638185029Spjd 639185029Spjd inp = sotoinpcb(so); 640185029Spjd if (inp == 0) 641185029Spjd return EINVAL; 642185029Spjd s = splnet(); 643185029Spjd in6_pcbdetach(inp); 644185029Spjd splx(s); 645185029Spjd return 0; 646185029Spjd} 647185029Spjd 648185029Spjdstatic int 649185029Spjdudp6_disconnect(struct socket *so) 650185029Spjd{ 651185029Spjd struct inpcb *inp; 652185029Spjd int s; 653168404Spjd 654168404Spjd inp = sotoinpcb(so); 655168404Spjd if (inp == 0) 656168404Spjd return EINVAL; 657168404Spjd 658168404Spjd#ifdef INET 659185029Spjd if (inp->inp_vflag & INP_IPV4) { 660185029Spjd struct pr_usrreqs *pru; 661185029Spjd 662185029Spjd pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 663168404Spjd return ((*pru->pru_disconnect)(so)); 664168404Spjd } 665168404Spjd#endif 666185029Spjd 667185029Spjd if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 668185029Spjd return ENOTCONN; 669185029Spjd 670185029Spjd s = splnet(); 671185029Spjd in6_pcbdisconnect(inp); 672185029Spjd inp->in6p_laddr = in6addr_any; 673185029Spjd splx(s); 674185029Spjd so->so_state &= ~SS_ISCONNECTED; /* XXX */ 675185029Spjd return 0; 676185029Spjd} 677185029Spjd 678185029Spjdstatic int 679185029Spjdudp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 680185029Spjd struct mbuf *control, struct thread *td) 681185029Spjd{ 682168404Spjd struct inpcb *inp; 683168404Spjd int error = 0; 684168404Spjd 685168404Spjd inp = sotoinpcb(so); 686168404Spjd if (inp == 0) { 687168404Spjd error = EINVAL; 688185029Spjd goto bad; 689185029Spjd } 690185029Spjd 691168404Spjd if (addr) { 692168404Spjd if (addr->sa_len != sizeof(struct sockaddr_in6)) { 693168404Spjd error = EINVAL; 694168404Spjd goto bad; 695168404Spjd } 696168404Spjd if (addr->sa_family != AF_INET6) { 697168404Spjd error = EAFNOSUPPORT; 698168404Spjd goto bad; 699168404Spjd } 700168404Spjd } 701168404Spjd 702185029Spjd#ifdef INET 703185029Spjd if (!ip6_v6only) { 704185029Spjd int hasv4addr; 705185029Spjd struct sockaddr_in6 *sin6 = 0; 706185029Spjd 707185029Spjd if (addr == 0) 708185029Spjd hasv4addr = (inp->inp_vflag & INP_IPV4); 709185029Spjd else { 710185029Spjd sin6 = (struct sockaddr_in6 *)addr; 711168404Spjd hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) 712209962Smm ? 1 : 0; 713209962Smm } 714209962Smm if (hasv4addr) { 715209962Smm struct pr_usrreqs *pru; 716209962Smm 717209962Smm if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { 718168404Spjd /* 719168404Spjd * since a user of this socket set the 720168404Spjd * IPV6_V6ONLY flag, we discard this 721168404Spjd * datagram destined to a v4 addr. 722185029Spjd */ 723168404Spjd return EINVAL; 724209962Smm } 725209962Smm if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && 726209962Smm !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) { 727209962Smm /* 728209962Smm * when remote addr is IPv4-mapped 729209962Smm * address, local addr should not be 730209962Smm * an IPv6 address; since you cannot 731209962Smm * determine how to map IPv6 source 732168404Spjd * address to IPv4. 733168404Spjd */ 734168404Spjd return EINVAL; 735168404Spjd } 736168404Spjd if (sin6) 737168404Spjd in6_sin6_2_sin_in_sock(addr); 738168404Spjd pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 739168404Spjd error = ((*pru->pru_send)(so, flags, m, addr, control, 740168404Spjd td)); 741168404Spjd /* addr will just be freed in sendit(). */ 742168404Spjd return error; 743168404Spjd } 744168404Spjd } 745168404Spjd#endif 746168404Spjd 747168404Spjd return udp6_output(inp, m, addr, control, td); 748168404Spjd 749168404Spjd bad: 750168404Spjd m_freem(m); 751168404Spjd return (error); 752168404Spjd} 753168404Spjd 754213197Smmstruct pr_usrreqs udp6_usrreqs = { 755213197Smm udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect, 756213197Smm pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect, 757168404Spjd pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp, 758168404Spjd pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown, 759168404Spjd in6_mapped_sockaddr, sosend, soreceive, sopoll, in_pcbsosetlabel 760168404Spjd}; 761168404Spjd