udp6_usrreq.c revision 96972
1/* $FreeBSD: head/sys/netinet6/udp6_usrreq.c 96972 2002-05-20 05:41:09Z tanimura $ */ 2/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * Copyright (c) 1982, 1986, 1989, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 66 */ 67 68#include "opt_inet.h" 69#include "opt_inet6.h" 70#include "opt_ipsec.h" 71 72#include <sys/param.h> 73#include <sys/errno.h> 74#include <sys/kernel.h> 75#include <sys/lock.h> 76#include <sys/mbuf.h> 77#include <sys/proc.h> 78#include <sys/protosw.h> 79#include <sys/signalvar.h> 80#include <sys/socket.h> 81#include <sys/socketvar.h> 82#include <sys/stat.h> 83#include <sys/sx.h> 84#include <sys/sysctl.h> 85#include <sys/syslog.h> 86#include <sys/systm.h> 87 88#include <net/if.h> 89#include <net/if_types.h> 90#include <net/route.h> 91 92#include <netinet/in.h> 93#include <netinet/in_pcb.h> 94#include <netinet/in_systm.h> 95#include <netinet/in_var.h> 96#include <netinet/ip.h> 97#include <netinet/ip6.h> 98#include <netinet/icmp6.h> 99#include <netinet/ip_var.h> 100#include <netinet/udp.h> 101#include <netinet/udp_var.h> 102#include <netinet6/ip6protosw.h> 103#include <netinet6/ip6_var.h> 104#include <netinet6/in6_pcb.h> 105#include <netinet6/udp6_var.h> 106 107#ifdef IPSEC 108#include <netinet6/ipsec.h> 109#include <netinet6/ipsec6.h> 110#endif /* IPSEC */ 111 112/* 113 * UDP protocol inplementation. 114 * Per RFC 768, August, 1980. 115 */ 116 117extern struct protosw inetsw[]; 118static int in6_mcmatch __P((struct inpcb *, struct in6_addr *, struct ifnet *)); 119static int udp6_detach __P((struct socket *so)); 120 121static int 122in6_mcmatch(in6p, ia6, ifp) 123 struct inpcb *in6p; 124 register struct in6_addr *ia6; 125 struct ifnet *ifp; 126{ 127 struct ip6_moptions *im6o = in6p->in6p_moptions; 128 struct in6_multi_mship *imm; 129 130 if (im6o == NULL) 131 return 0; 132 133 for (imm = im6o->im6o_memberships.lh_first; imm != NULL; 134 imm = imm->i6mm_chain.le_next) { 135 if ((ifp == NULL || 136 imm->i6mm_maddr->in6m_ifp == ifp) && 137 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, 138 ia6)) 139 return 1; 140 } 141 return 0; 142} 143 144int 145udp6_input(mp, offp, proto) 146 struct mbuf **mp; 147 int *offp, proto; 148{ 149 struct mbuf *m = *mp; 150 register struct ip6_hdr *ip6; 151 register struct udphdr *uh; 152 register struct inpcb *in6p; 153 struct mbuf *opts = NULL; 154 int off = *offp; 155 int plen, ulen; 156 struct sockaddr_in6 udp_in6; 157 158 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 159 160 ip6 = mtod(m, struct ip6_hdr *); 161 162 if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) { 163 /* XXX send icmp6 host/port unreach? */ 164 m_freem(m); 165 return IPPROTO_DONE; 166 } 167 168 udpstat.udps_ipackets++; 169 170 plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 171 uh = (struct udphdr *)((caddr_t)ip6 + off); 172 ulen = ntohs((u_short)uh->uh_ulen); 173 174 if (plen != ulen) { 175 udpstat.udps_badlen++; 176 goto bad; 177 } 178 179 /* 180 * Checksum extended UDP header and data. 181 */ 182 if (uh->uh_sum == 0) 183 udpstat.udps_nosum++; 184 else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { 185 udpstat.udps_badsum++; 186 goto bad; 187 } 188 189 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 190 struct inpcb *last; 191 192 /* 193 * Deliver a multicast datagram to all sockets 194 * for which the local and remote addresses and ports match 195 * those of the incoming datagram. This allows more than 196 * one process to receive multicasts on the same port. 197 * (This really ought to be done for unicast datagrams as 198 * well, but that would cause problems with existing 199 * applications that open both address-specific sockets and 200 * a wildcard socket listening to the same port -- they would 201 * end up receiving duplicates of every unicast datagram. 202 * Those applications open the multiple sockets to overcome an 203 * inadequacy of the UDP socket interface, but for backwards 204 * compatibility we avoid the problem here rather than 205 * fixing the interface. Maybe 4.5BSD will remedy this?) 206 */ 207 208 /* 209 * In a case that laddr should be set to the link-local 210 * address (this happens in RIPng), the multicast address 211 * specified in the received packet does not match with 212 * laddr. To cure this situation, the matching is relaxed 213 * if the receiving interface is the same as one specified 214 * in the socket and if the destination multicast address 215 * matches one of the multicast groups specified in the socket. 216 */ 217 218 /* 219 * Construct sockaddr format source address. 220 */ 221 init_sin6(&udp_in6, m); /* general init */ 222 udp_in6.sin6_port = uh->uh_sport; 223 /* 224 * KAME note: traditionally we dropped udpiphdr from mbuf here. 225 * We need udphdr for IPsec processing so we do that later. 226 */ 227 228 /* 229 * Locate pcb(s) for datagram. 230 * (Algorithm copied from raw_intr().) 231 */ 232 last = NULL; 233 LIST_FOREACH(in6p, &udb, inp_list) { 234 if ((in6p->inp_vflag & INP_IPV6) == 0) 235 continue; 236 if (in6p->in6p_lport != uh->uh_dport) 237 continue; 238 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { 239 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, 240 &ip6->ip6_dst) && 241 !in6_mcmatch(in6p, &ip6->ip6_dst, 242 m->m_pkthdr.rcvif)) 243 continue; 244 } 245 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 246 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, 247 &ip6->ip6_src) || 248 in6p->in6p_fport != uh->uh_sport) 249 continue; 250 } 251 252 if (last != NULL) { 253 struct mbuf *n; 254 255#ifdef IPSEC 256 /* 257 * Check AH/ESP integrity. 258 */ 259 if (ipsec6_in_reject_so(m, last->inp_socket)) 260 ipsec6stat.in_polvio++; 261 /* do not inject data into pcb */ 262 else 263#endif /* IPSEC */ 264 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { 265 /* 266 * KAME NOTE: do not 267 * m_copy(m, offset, ...) above. 268 * sbappendaddr() expects M_PKTHDR, 269 * and m_copy() will copy M_PKTHDR 270 * only if offset is 0. 271 */ 272 if (last->in6p_flags & IN6P_CONTROLOPTS) 273 ip6_savecontrol(last, &opts, 274 ip6, n); 275 else { 276 SOCK_LOCK(last->in6p_socket); 277 if (last->in6p_socket->so_options & SO_TIMESTAMP) { 278 SOCK_UNLOCK(last->in6p_socket); 279 ip6_savecontrol(last, &opts, 280 ip6, n); 281 } else 282 SOCK_UNLOCK(last->in6p_socket); 283 } 284 285 m_adj(n, off + sizeof(struct udphdr)); 286 if (sbappendaddr(&last->in6p_socket->so_rcv, 287 (struct sockaddr *)&udp_in6, 288 n, opts) == 0) { 289 m_freem(n); 290 if (opts) 291 m_freem(opts); 292 udpstat.udps_fullsock++; 293 } else { 294 SOCK_LOCK(last->in6p_socket); 295 sorwakeup(last->in6p_socket); 296 SOCK_UNLOCK(last->in6p_socket); 297 } 298 opts = NULL; 299 } 300 } 301 last = in6p; 302 /* 303 * Don't look for additional matches if this one does 304 * not have either the SO_REUSEPORT or SO_REUSEADDR 305 * socket options set. This heuristic avoids searching 306 * through all pcbs in the common case of a non-shared 307 * port. It assumes that an application will never 308 * clear these options after setting them. 309 */ 310 SOCK_LOCK(last->in6p_socket); 311 if ((last->in6p_socket->so_options & 312 (SO_REUSEPORT|SO_REUSEADDR)) == 0) { 313 SOCK_UNLOCK(last->in6p_socket); 314 break; 315 } else 316 SOCK_UNLOCK(last->in6p_socket); 317 } 318 319 if (last == NULL) { 320 /* 321 * No matching pcb found; discard datagram. 322 * (No need to send an ICMP Port Unreachable 323 * for a broadcast or multicast datgram.) 324 */ 325 udpstat.udps_noport++; 326 udpstat.udps_noportmcast++; 327 goto bad; 328 } 329#ifdef IPSEC 330 /* 331 * Check AH/ESP integrity. 332 */ 333 if (ipsec6_in_reject_so(m, last->inp_socket)) { 334 ipsec6stat.in_polvio++; 335 goto bad; 336 } 337#endif /* IPSEC */ 338 if (last->in6p_flags & IN6P_CONTROLOPTS) 339 ip6_savecontrol(last, &opts, ip6, m); 340 else { 341 SOCK_LOCK(last->in6p_socket); 342 if (last->in6p_socket->so_options & SO_TIMESTAMP) { 343 SOCK_UNLOCK(last->in6p_socket); 344 ip6_savecontrol(last, &opts, ip6, m); 345 } else 346 SOCK_UNLOCK(last->in6p_socket); 347 } 348 349 m_adj(m, off + sizeof(struct udphdr)); 350 if (sbappendaddr(&last->in6p_socket->so_rcv, 351 (struct sockaddr *)&udp_in6, 352 m, opts) == 0) { 353 udpstat.udps_fullsock++; 354 goto bad; 355 } 356 SOCK_LOCK(last->in6p_socket); 357 sorwakeup(last->in6p_socket); 358 SOCK_UNLOCK(last->in6p_socket); 359 return IPPROTO_DONE; 360 } 361 /* 362 * Locate pcb for datagram. 363 */ 364 in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport, 365 &ip6->ip6_dst, uh->uh_dport, 1, 366 m->m_pkthdr.rcvif); 367 if (in6p == 0) { 368 if (log_in_vain) { 369 char buf[INET6_ADDRSTRLEN]; 370 371 strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); 372 log(LOG_INFO, 373 "Connection attempt to UDP %s:%d from %s:%d\n", 374 buf, ntohs(uh->uh_dport), 375 ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); 376 } 377 udpstat.udps_noport++; 378 if (m->m_flags & M_MCAST) { 379 printf("UDP6: M_MCAST is set in a unicast packet.\n"); 380 udpstat.udps_noportmcast++; 381 goto bad; 382 } 383 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 384 return IPPROTO_DONE; 385 } 386#ifdef IPSEC 387 /* 388 * Check AH/ESP integrity. 389 */ 390 if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { 391 ipsec6stat.in_polvio++; 392 goto bad; 393 } 394#endif /* IPSEC */ 395 396 /* 397 * Construct sockaddr format source address. 398 * Stuff source address and datagram in user buffer. 399 */ 400 init_sin6(&udp_in6, m); /* general init */ 401 udp_in6.sin6_port = uh->uh_sport; 402 if (in6p->in6p_flags & IN6P_CONTROLOPTS) 403 ip6_savecontrol(in6p, &opts, ip6, m); 404 else { 405 SOCK_LOCK(in6p->in6p_socket); 406 if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { 407 SOCK_UNLOCK(in6p->in6p_socket); 408 ip6_savecontrol(in6p, &opts, ip6, m); 409 } else 410 SOCK_UNLOCK(in6p->in6p_socket); 411 } 412 m_adj(m, off + sizeof(struct udphdr)); 413 if (sbappendaddr(&in6p->in6p_socket->so_rcv, 414 (struct sockaddr *)&udp_in6, 415 m, opts) == 0) { 416 udpstat.udps_fullsock++; 417 goto bad; 418 } 419 SOCK_LOCK(in6p->in6p_socket); 420 sorwakeup(in6p->in6p_socket); 421 SOCK_UNLOCK(in6p->in6p_socket); 422 return IPPROTO_DONE; 423bad: 424 if (m) 425 m_freem(m); 426 if (opts) 427 m_freem(opts); 428 return IPPROTO_DONE; 429} 430 431void 432udp6_ctlinput(cmd, sa, d) 433 int cmd; 434 struct sockaddr *sa; 435 void *d; 436{ 437 struct udphdr uh; 438 struct ip6_hdr *ip6; 439 struct mbuf *m; 440 int off = 0; 441 struct ip6ctlparam *ip6cp = NULL; 442 const struct sockaddr_in6 *sa6_src = NULL; 443 void (*notify) __P((struct inpcb *, int)) = udp_notify; 444 struct udp_portonly { 445 u_int16_t uh_sport; 446 u_int16_t uh_dport; 447 } *uhp; 448 449 if (sa->sa_family != AF_INET6 || 450 sa->sa_len != sizeof(struct sockaddr_in6)) 451 return; 452 453 if ((unsigned)cmd >= PRC_NCMDS) 454 return; 455 if (PRC_IS_REDIRECT(cmd)) 456 notify = in6_rtchange, d = NULL; 457 else if (cmd == PRC_HOSTDEAD) 458 d = NULL; 459 else if (inet6ctlerrmap[cmd] == 0) 460 return; 461 462 /* if the parameter is from icmp6, decode it. */ 463 if (d != NULL) { 464 ip6cp = (struct ip6ctlparam *)d; 465 m = ip6cp->ip6c_m; 466 ip6 = ip6cp->ip6c_ip6; 467 off = ip6cp->ip6c_off; 468 sa6_src = ip6cp->ip6c_src; 469 } else { 470 m = NULL; 471 ip6 = NULL; 472 sa6_src = &sa6_any; 473 } 474 475 if (ip6) { 476 /* 477 * XXX: We assume that when IPV6 is non NULL, 478 * M and OFF are valid. 479 */ 480 481 /* check if we can safely examine src and dst ports */ 482 if (m->m_pkthdr.len < off + sizeof(*uhp)) 483 return; 484 485 bzero(&uh, sizeof(uh)); 486 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); 487 488 (void) in6_pcbnotify(&udb, sa, uh.uh_dport, 489 (struct sockaddr *)ip6cp->ip6c_src, 490 uh.uh_sport, cmd, notify); 491 } else 492 (void) in6_pcbnotify(&udb, sa, 0, 493 (const struct sockaddr *)sa6_src, 494 0, cmd, notify); 495} 496 497static int 498udp6_getcred(SYSCTL_HANDLER_ARGS) 499{ 500 struct xucred xuc; 501 struct sockaddr_in6 addrs[2]; 502 struct inpcb *inp; 503 int error, s; 504 505 error = suser(req->td); 506 if (error) 507 return (error); 508 509 if (req->newlen != sizeof(addrs)) 510 return (EINVAL); 511 if (req->oldlen != sizeof(struct xucred)) 512 return (EINVAL); 513 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 514 if (error) 515 return (error); 516 s = splnet(); 517 inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr, 518 addrs[1].sin6_port, 519 &addrs[0].sin6_addr, addrs[0].sin6_port, 520 1, NULL); 521 if (!inp || !inp->inp_socket) { 522 error = ENOENT; 523 goto out; 524 } 525 cru2x(inp->inp_socket->so_cred, &xuc); 526 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 527out: 528 splx(s); 529 return (error); 530} 531 532SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 533 0, 0, 534 udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); 535 536static int 537udp6_abort(struct socket *so) 538{ 539 struct inpcb *inp; 540 int s; 541 542 inp = sotoinpcb(so); 543 if (inp == 0) 544 return EINVAL; /* ??? possible? panic instead? */ 545 SOCK_LOCK(so); 546 soisdisconnected(so); 547 SOCK_UNLOCK(so); 548 s = splnet(); 549 in6_pcbdetach(inp); 550 splx(s); 551 return 0; 552} 553 554static int 555udp6_attach(struct socket *so, int proto, struct thread *td) 556{ 557 struct inpcb *inp; 558 int s, error; 559 560 inp = sotoinpcb(so); 561 if (inp != 0) 562 return EINVAL; 563 564 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 565 error = soreserve(so, udp_sendspace, udp_recvspace); 566 if (error) 567 return error; 568 } 569 s = splnet(); 570 error = in_pcballoc(so, &udbinfo, td); 571 splx(s); 572 if (error) 573 return error; 574 inp = (struct inpcb *)so->so_pcb; 575 inp->inp_vflag |= INP_IPV6; 576 inp->in6p_hops = -1; /* use kernel default */ 577 inp->in6p_cksum = -1; /* just to be sure */ 578 /* 579 * XXX: ugly!! 580 * IPv4 TTL initialization is necessary for an IPv6 socket as well, 581 * because the socket may be bound to an IPv6 wildcard address, 582 * which may match an IPv4-mapped IPv6 address. 583 */ 584 inp->inp_ip_ttl = ip_defttl; 585 return 0; 586} 587 588static int 589udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 590{ 591 struct inpcb *inp; 592 int s, error; 593 594 inp = sotoinpcb(so); 595 if (inp == 0) 596 return EINVAL; 597 598 inp->inp_vflag &= ~INP_IPV4; 599 inp->inp_vflag |= INP_IPV6; 600 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 601 struct sockaddr_in6 *sin6_p; 602 603 sin6_p = (struct sockaddr_in6 *)nam; 604 605 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 606 inp->inp_vflag |= INP_IPV4; 607 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 608 struct sockaddr_in sin; 609 610 in6_sin6_2_sin(&sin, sin6_p); 611 inp->inp_vflag |= INP_IPV4; 612 inp->inp_vflag &= ~INP_IPV6; 613 s = splnet(); 614 error = in_pcbbind(inp, (struct sockaddr *)&sin, td); 615 splx(s); 616 return error; 617 } 618 } 619 620 s = splnet(); 621 error = in6_pcbbind(inp, nam, td); 622 splx(s); 623 return error; 624} 625 626static int 627udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 628{ 629 struct inpcb *inp; 630 int s, error; 631 632 inp = sotoinpcb(so); 633 if (inp == 0) 634 return EINVAL; 635 636 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { 637 struct sockaddr_in6 *sin6_p; 638 639 sin6_p = (struct sockaddr_in6 *)nam; 640 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 641 struct sockaddr_in sin; 642 643 if (inp->inp_faddr.s_addr != INADDR_ANY) 644 return EISCONN; 645 in6_sin6_2_sin(&sin, sin6_p); 646 s = splnet(); 647 error = in_pcbconnect(inp, (struct sockaddr *)&sin, td); 648 splx(s); 649 if (error == 0) { 650 inp->inp_vflag |= INP_IPV4; 651 inp->inp_vflag &= ~INP_IPV6; 652 SOCK_LOCK(so); 653 soisconnected(so); 654 SOCK_UNLOCK(so); 655 } 656 return error; 657 } 658 } 659 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 660 return EISCONN; 661 s = splnet(); 662 error = in6_pcbconnect(inp, nam, td); 663 splx(s); 664 if (error == 0) { 665 if (ip6_mapped_addr_on) { /* should be non mapped addr */ 666 inp->inp_vflag &= ~INP_IPV4; 667 inp->inp_vflag |= INP_IPV6; 668 } 669 SOCK_LOCK(so); 670 soisconnected(so); 671 SOCK_UNLOCK(so); 672 } 673 return error; 674} 675 676static int 677udp6_detach(struct socket *so) 678{ 679 struct inpcb *inp; 680 int s; 681 682 inp = sotoinpcb(so); 683 if (inp == 0) 684 return EINVAL; 685 s = splnet(); 686 in6_pcbdetach(inp); 687 splx(s); 688 return 0; 689} 690 691static int 692udp6_disconnect(struct socket *so) 693{ 694 struct inpcb *inp; 695 int s; 696 697 inp = sotoinpcb(so); 698 if (inp == 0) 699 return EINVAL; 700 701 if (inp->inp_vflag & INP_IPV4) { 702 struct pr_usrreqs *pru; 703 704 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 705 return ((*pru->pru_disconnect)(so)); 706 } 707 708 if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) 709 return ENOTCONN; 710 711 s = splnet(); 712 in6_pcbdisconnect(inp); 713 inp->in6p_laddr = in6addr_any; 714 splx(s); 715 SOCK_LOCK(so); 716 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 717 SOCK_UNLOCK(so); 718 return 0; 719} 720 721static int 722udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 723 struct mbuf *control, struct thread *td) 724{ 725 struct inpcb *inp; 726 int error = 0; 727 728 inp = sotoinpcb(so); 729 if (inp == 0) { 730 error = EINVAL; 731 goto bad; 732 } 733 734 if (addr) { 735 if (addr->sa_len != sizeof(struct sockaddr_in6)) { 736 error = EINVAL; 737 goto bad; 738 } 739 if (addr->sa_family != AF_INET6) { 740 error = EAFNOSUPPORT; 741 goto bad; 742 } 743 } 744 745 if (ip6_mapped_addr_on) { 746 int hasv4addr; 747 struct sockaddr_in6 *sin6 = 0; 748 749 if (addr == 0) 750 hasv4addr = (inp->inp_vflag & INP_IPV4); 751 else { 752 sin6 = (struct sockaddr_in6 *)addr; 753 hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) 754 ? 1 : 0; 755 } 756 if (hasv4addr) { 757 struct pr_usrreqs *pru; 758 759 if (sin6) 760 in6_sin6_2_sin_in_sock(addr); 761 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; 762 error = ((*pru->pru_send)(so, flags, m, addr, control, 763 td)); 764 /* addr will just be freed in sendit(). */ 765 return error; 766 } 767 } 768 769 return udp6_output(inp, m, addr, control, td); 770 771 bad: 772 m_freem(m); 773 return(error); 774} 775 776struct pr_usrreqs udp6_usrreqs = { 777 udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect, 778 pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect, 779 pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp, 780 pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown, 781 in6_mapped_sockaddr, sosend, soreceive, sopoll 782}; 783