1 /* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.13 2003/01/24 05:11:35 sam Exp $ */ 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. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 62 */ 63 64 #include "opt_inet.h" 65 #include "opt_inet6.h" 66 67 #include <sys/param.h> 68 #include <sys/kernel.h> 69 #include <sys/malloc.h> 70 #include <sys/mbuf.h> 71 #include <sys/protosw.h> 72 #include <sys/socket.h> 73 #include <sys/socketvar.h> 74 #include <sys/sysctl.h> 75 #include <sys/errno.h> 76 #include <sys/stat.h> 77 #include <sys/systm.h> 78 #include <sys/syslog.h> 79 #include <sys/proc.h> 80 #include <sys/caps.h> 81 #include <sys/jail.h> 82 83 #include <sys/thread2.h> 84 #include <sys/socketvar2.h> 85 #include <sys/msgport2.h> 86 87 #include <net/if.h> 88 #include <net/route.h> 89 #include <net/if_types.h> 90 #include <net/netisr2.h> 91 92 #include <netinet/in.h> 93 #include <netinet/in_systm.h> 94 #include <netinet/ip.h> 95 #include <netinet/in_pcb.h> 96 #include <netinet/in_var.h> 97 #include <netinet/ip_var.h> 98 #include <netinet/udp.h> 99 #include <netinet/udp_var.h> 100 #include <netinet/ip6.h> 101 #include <netinet6/ip6_var.h> 102 #include <netinet6/in6_pcb.h> 103 #include <netinet/icmp6.h> 104 #include <netinet6/udp6_var.h> 105 #include <netinet6/ip6protosw.h> 106 107 /* 108 * UDP protocol inplementation. 109 * Per RFC 768, August, 1980. 110 */ 111 112 extern struct protosw inetsw[]; 113 static int in6_mcmatch (struct inpcb *, struct in6_addr *, struct ifnet *); 114 115 static int 116 in6_mcmatch(struct inpcb *in6p, struct in6_addr *ia6, struct ifnet *ifp) 117 { 118 struct ip6_moptions *im6o = in6p->in6p_moptions; 119 struct in6_multi_mship *imm; 120 121 if (im6o == NULL) 122 return 0; 123 124 for (imm = im6o->im6o_memberships.lh_first; imm != NULL; 125 imm = imm->i6mm_chain.le_next) { 126 if ((ifp == NULL || 127 imm->i6mm_maddr->in6m_ifp == ifp) && 128 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, 129 ia6)) 130 return 1; 131 } 132 return 0; 133 } 134 135 int 136 udp6_input(struct mbuf **mp, int *offp, int proto) 137 { 138 struct mbuf *m = *mp; 139 struct ip6_hdr *ip6; 140 struct udphdr *uh; 141 struct inpcb *in6p; 142 struct mbuf *opts = NULL; 143 int off = *offp; 144 int plen, ulen; 145 struct sockaddr_in6 udp_in6; 146 struct socket *so; 147 struct inpcbinfo *pcbinfo = &udbinfo[0]; 148 149 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); 150 151 ip6 = mtod(m, struct ip6_hdr *); 152 153 udp_stat.udps_ipackets++; 154 155 plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); 156 uh = (struct udphdr *)((caddr_t)ip6 + off); 157 ulen = ntohs((u_short)uh->uh_ulen); 158 159 if (plen != ulen) { 160 udp_stat.udps_badlen++; 161 goto bad; 162 } 163 164 /* 165 * Checksum extended UDP header and data. 166 */ 167 if (uh->uh_sum == 0) 168 udp_stat.udps_nosum++; 169 else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { 170 udp_stat.udps_badsum++; 171 goto bad; 172 } 173 174 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 175 struct inpcb *last, *marker; 176 177 /* 178 * Deliver a multicast datagram to all sockets 179 * for which the local and remote addresses and ports match 180 * those of the incoming datagram. This allows more than 181 * one process to receive multicasts on the same port. 182 * (This really ought to be done for unicast datagrams as 183 * well, but that would cause problems with existing 184 * applications that open both address-specific sockets and 185 * a wildcard socket listening to the same port -- they would 186 * end up receiving duplicates of every unicast datagram. 187 * Those applications open the multiple sockets to overcome an 188 * inadequacy of the UDP socket interface, but for backwards 189 * compatibility we avoid the problem here rather than 190 * fixing the interface. Maybe 4.5BSD will remedy this?) 191 */ 192 193 /* 194 * In a case that laddr should be set to the link-local 195 * address (this happens in RIPng), the multicast address 196 * specified in the received packet does not match with 197 * laddr. To cure this situation, the matching is relaxed 198 * if the receiving interface is the same as one specified 199 * in the socket and if the destination multicast address 200 * matches one of the multicast groups specified in the socket. 201 */ 202 203 /* 204 * Construct sockaddr format source address. 205 */ 206 init_sin6(&udp_in6, m); /* general init */ 207 udp_in6.sin6_port = uh->uh_sport; 208 /* 209 * KAME note: traditionally we dropped udpiphdr from mbuf here. 210 */ 211 212 /* 213 * Locate pcb(s) for datagram. 214 * (Algorithm copied from raw_intr().) 215 */ 216 last = NULL; 217 218 marker = in_pcbmarker(); 219 220 GET_PCBINFO_TOKEN(pcbinfo); 221 222 LIST_INSERT_HEAD(&pcbinfo->pcblisthead, marker, inp_list); 223 while ((in6p = LIST_NEXT(marker, inp_list)) != NULL) { 224 LIST_REMOVE(marker, inp_list); 225 LIST_INSERT_AFTER(in6p, marker, inp_list); 226 227 if (in6p->inp_flags & INP_PLACEMARKER) 228 continue; 229 if (!INP_ISIPV6(in6p)) 230 continue; 231 if (in6p->in6p_lport != uh->uh_dport) 232 continue; 233 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { 234 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, 235 &ip6->ip6_dst) && 236 !in6_mcmatch(in6p, &ip6->ip6_dst, 237 m->m_pkthdr.rcvif)) 238 continue; 239 } 240 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 241 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, 242 &ip6->ip6_src) || 243 in6p->in6p_fport != uh->uh_sport) 244 continue; 245 } 246 247 if (last != NULL) { 248 struct mbuf *n; 249 250 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 251 if (n != NULL) { 252 /* 253 * KAME NOTE: do not 254 * m_copym(m, offset, ...) above. 255 * ssb_appendaddr() expects M_PKTHDR, 256 * and m_copym() will copy M_PKTHDR 257 * only if offset is 0. 258 */ 259 so = last->in6p_socket; 260 if ((last->in6p_flags & IN6P_CONTROLOPTS) || 261 (so->so_options & SO_TIMESTAMP)) { 262 ip6_savecontrol(last, &opts, 263 ip6, n); 264 } 265 m_adj(n, off + sizeof(struct udphdr)); 266 lwkt_gettoken(&so->so_rcv.ssb_token); 267 if (ssb_appendaddr(&so->so_rcv, 268 (struct sockaddr *)&udp_in6, 269 n, opts) == 0) { 270 m_freem(n); 271 if (opts) 272 m_freem(opts); 273 udp_stat.udps_fullsock++; 274 soroverflow(so); 275 } else { 276 sorwakeup(so); 277 } 278 lwkt_reltoken(&so->so_rcv.ssb_token); 279 opts = NULL; 280 } 281 } 282 last = in6p; 283 /* 284 * Don't look for additional matches if this one does 285 * not have either the SO_REUSEPORT or SO_REUSEADDR 286 * socket options set. This heuristic avoids searching 287 * through all pcbs in the common case of a non-shared 288 * port. It assumes that an application will never 289 * clear these options after setting them. 290 */ 291 if ((last->in6p_socket->so_options & 292 (SO_REUSEPORT | SO_REUSEADDR)) == 0) 293 break; 294 } 295 LIST_REMOVE(marker, inp_list); 296 297 REL_PCBINFO_TOKEN(pcbinfo); 298 299 if (last == NULL) { 300 /* 301 * No matching pcb found; discard datagram. 302 * (No need to send an ICMP Port Unreachable 303 * for a broadcast or multicast datgram.) 304 */ 305 udp_stat.udps_noport++; 306 udp_stat.udps_noportmcast++; 307 goto bad; 308 } 309 if (last->in6p_flags & IN6P_CONTROLOPTS 310 || last->in6p_socket->so_options & SO_TIMESTAMP) 311 ip6_savecontrol(last, &opts, ip6, m); 312 313 m_adj(m, off + sizeof(struct udphdr)); 314 so = last->in6p_socket; 315 lwkt_gettoken(&so->so_rcv.ssb_token); 316 if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&udp_in6, 317 m, opts) == 0) { 318 udp_stat.udps_fullsock++; 319 soroverflow(so); 320 lwkt_reltoken(&so->so_rcv.ssb_token); 321 goto bad; 322 } 323 sorwakeup(so); 324 lwkt_reltoken(&so->so_rcv.ssb_token); 325 return IPPROTO_DONE; 326 } 327 /* 328 * Locate pcb for datagram. 329 */ 330 in6p = in6_pcblookup_hash(pcbinfo, &ip6->ip6_src, uh->uh_sport, 331 &ip6->ip6_dst, uh->uh_dport, 1, 332 m->m_pkthdr.rcvif); 333 if (in6p == NULL) { 334 if (log_in_vain) { 335 char buf[INET6_ADDRSTRLEN]; 336 337 strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); 338 log(LOG_INFO, 339 "Connection attempt to UDP [%s]:%d from [%s]:%d\n", 340 buf, ntohs(uh->uh_dport), 341 ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); 342 } 343 udp_stat.udps_noport++; 344 if (m->m_flags & M_MCAST) { 345 kprintf("UDP6: M_MCAST is set in a unicast packet.\n"); 346 udp_stat.udps_noportmcast++; 347 goto bad; 348 } 349 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); 350 return IPPROTO_DONE; 351 } 352 353 /* 354 * Construct sockaddr format source address. 355 * Stuff source address and datagram in user buffer. 356 */ 357 init_sin6(&udp_in6, m); /* general init */ 358 udp_in6.sin6_port = uh->uh_sport; 359 if (in6p->in6p_flags & IN6P_CONTROLOPTS 360 || in6p->in6p_socket->so_options & SO_TIMESTAMP) 361 ip6_savecontrol(in6p, &opts, ip6, m); 362 m_adj(m, off + sizeof(struct udphdr)); 363 so = in6p->in6p_socket; 364 lwkt_gettoken(&so->so_rcv.ssb_token); 365 if (ssb_appendaddr(&so->so_rcv, (struct sockaddr *)&udp_in6, 366 m, opts) == 0) { 367 udp_stat.udps_fullsock++; 368 soroverflow(so); 369 lwkt_reltoken(&so->so_rcv.ssb_token); 370 goto bad; 371 } 372 sorwakeup(so); 373 lwkt_reltoken(&so->so_rcv.ssb_token); 374 return IPPROTO_DONE; 375 bad: 376 if (m) 377 m_freem(m); 378 if (opts) 379 m_freem(opts); 380 return IPPROTO_DONE; 381 } 382 383 void 384 udp6_ctlinput(netmsg_t msg) 385 { 386 int cmd = msg->ctlinput.nm_cmd; 387 struct sockaddr *sa = msg->ctlinput.nm_arg; 388 void *d = msg->ctlinput.nm_extra; 389 struct udphdr uh; 390 struct ip6_hdr *ip6; 391 struct mbuf *m; 392 int off = 0; 393 struct ip6ctlparam *ip6cp = NULL; 394 const struct sockaddr_in6 *sa6_src = NULL; 395 inp_notify_t notify = udp_notify; 396 struct udp_portonly { 397 u_int16_t uh_sport; 398 u_int16_t uh_dport; 399 } *uhp; 400 401 if (sa->sa_family != AF_INET6 || 402 sa->sa_len != sizeof(struct sockaddr_in6)) 403 goto out; 404 405 if ((unsigned)cmd >= PRC_NCMDS) 406 goto out; 407 if (PRC_IS_REDIRECT(cmd)) 408 notify = in6_rtchange, d = NULL; 409 else if (cmd == PRC_HOSTDEAD) 410 d = NULL; 411 else if (inet6ctlerrmap[cmd] == 0) 412 goto out; 413 414 /* if the parameter is from icmp6, decode it. */ 415 if (d != NULL) { 416 ip6cp = (struct ip6ctlparam *)d; 417 m = ip6cp->ip6c_m; 418 ip6 = ip6cp->ip6c_ip6; 419 off = ip6cp->ip6c_off; 420 sa6_src = ip6cp->ip6c_src; 421 } else { 422 m = NULL; 423 ip6 = NULL; 424 sa6_src = &sa6_any; 425 } 426 427 if (ip6) { 428 /* 429 * XXX: We assume that when IPV6 is non NULL, 430 * M and OFF are valid. 431 */ 432 433 /* check if we can safely examine src and dst ports */ 434 if (m->m_pkthdr.len < off + sizeof(*uhp)) 435 return; 436 437 bzero(&uh, sizeof(uh)); 438 m_copydata(m, off, sizeof(*uhp), &uh); 439 440 in6_pcbnotify(&udbinfo[0], sa, uh.uh_dport, 441 (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, 442 cmd, 0, notify); 443 } else { 444 in6_pcbnotify(&udbinfo[0], sa, 0, 445 (const struct sockaddr *)sa6_src, 0, 446 cmd, 0, notify); 447 } 448 out: 449 lwkt_replymsg(&msg->ctlinput.base.lmsg, 0); 450 } 451 452 static int 453 udp6_getcred(SYSCTL_HANDLER_ARGS) 454 { 455 struct sockaddr_in6 addrs[2]; 456 struct inpcb *inp; 457 int error; 458 459 error = caps_priv_check_td(req->td, SYSCAP_RESTRICTEDROOT); 460 if (error) 461 return (error); 462 463 if (req->newlen != sizeof(addrs)) 464 return (EINVAL); 465 if (req->oldlen != sizeof(struct ucred)) 466 return (EINVAL); 467 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 468 if (error) 469 return (error); 470 crit_enter(); 471 inp = in6_pcblookup_hash(&udbinfo[0], &addrs[1].sin6_addr, 472 addrs[1].sin6_port, 473 &addrs[0].sin6_addr, addrs[0].sin6_port, 474 1, NULL); 475 if (!inp || !inp->inp_socket) { 476 error = ENOENT; 477 goto out; 478 } 479 error = SYSCTL_OUT(req, inp->inp_socket->so_cred, 480 sizeof(struct ucred)); 481 482 out: 483 crit_exit(); 484 return (error); 485 } 486 487 SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 488 0, 0, 489 udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection"); 490 491 /* 492 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 493 * will sofree() it when we return. 494 */ 495 static void 496 udp6_abort(netmsg_t msg) 497 { 498 struct socket *so = msg->abort.base.nm_so; 499 struct inpcb *inp; 500 int error; 501 502 inp = so->so_pcb; 503 if (inp) { 504 soisdisconnected(so); 505 506 in6_pcbdetach(inp); 507 error = 0; 508 } else { 509 error = EINVAL; 510 } 511 lwkt_replymsg(&msg->abort.base.lmsg, error); 512 } 513 514 static void 515 udp6_attach(netmsg_t msg) 516 { 517 struct socket *so = msg->attach.base.nm_so; 518 struct pru_attach_info *ai = msg->attach.nm_ai; 519 struct inpcb *inp; 520 int error; 521 522 inp = so->so_pcb; 523 if (inp != NULL) { 524 error = EINVAL; 525 goto out; 526 } 527 528 if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) { 529 error = soreserve(so, udp_sendspace, udp_recvspace, 530 ai->sb_rlimit); 531 if (error) 532 goto out; 533 } 534 535 error = in_pcballoc(so, &udbinfo[0]); 536 if (error) 537 goto out; 538 539 inp = (struct inpcb *)so->so_pcb; 540 inp->in6p_hops = -1; /* use kernel default */ 541 inp->in6p_cksum = -1; /* just to be sure */ 542 /* 543 * XXX: ugly!! 544 * IPv4 TTL initialization is necessary for an IPv6 socket as well, 545 * because the socket may be bound to an IPv6 wildcard address, 546 * which may match an IPv4-mapped IPv6 address. 547 */ 548 inp->inp_ip_ttl = ip_defttl; 549 error = 0; 550 out: 551 lwkt_replymsg(&msg->attach.base.lmsg, error); 552 } 553 554 static void 555 udp6_bind(netmsg_t msg) 556 { 557 struct socket *so =msg->bind.base.nm_so; 558 struct sockaddr *nam = msg->bind.nm_nam; 559 struct thread *td = msg->bind.nm_td; 560 struct sockaddr_in6 *sin6_p = (struct sockaddr_in6 *)nam; 561 struct inpcb *inp; 562 int error; 563 564 inp = so->so_pcb; 565 if (inp == NULL) { 566 error = EINVAL; 567 goto out; 568 } 569 570 error = in6_pcbbind(inp, nam, td); 571 if (error == 0) { 572 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) 573 inp->inp_flags |= INP_WASBOUND_NOTANY; 574 in_pcbinswildcardhash(inp); 575 } 576 out: 577 lwkt_replymsg(&msg->bind.base.lmsg, error); 578 } 579 580 static void 581 udp6_connect(netmsg_t msg) 582 { 583 struct socket *so = msg->connect.base.nm_so; 584 struct sockaddr *nam = msg->connect.nm_nam; 585 struct thread *td = msg->connect.nm_td; 586 struct sockaddr_in6 *sin6_p; 587 struct inpcb *inp; 588 int error; 589 590 inp = so->so_pcb; 591 if (inp == NULL) { 592 error = EINVAL; 593 goto out; 594 } 595 596 sin6_p = (struct sockaddr_in6 *)nam; 597 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 598 error = EADDRNOTAVAIL; 599 goto out; 600 } 601 602 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 603 error = EISCONN; 604 goto out; 605 } 606 if (inp->inp_flags & INP_WILDCARD) 607 in_pcbremwildcardhash(inp); 608 error = in6_pcbconnect(inp, nam, td); 609 if (error == 0) { 610 soisconnected(so); 611 } else if (error == EAFNOSUPPORT) { /* connection dissolved */ 612 /* 613 * Follow traditional BSD behavior and retain 614 * the local port binding. But, fix the old misbehavior 615 * of overwriting any previously bound local address. 616 */ 617 if (!(inp->inp_flags & INP_WASBOUND_NOTANY)) 618 inp->in6p_laddr = kin6addr_any; 619 in_pcbinswildcardhash(inp); 620 } 621 out: 622 lwkt_replymsg(&msg->connect.base.lmsg, error); 623 } 624 625 static void 626 udp6_detach(netmsg_t msg) 627 { 628 struct socket *so = msg->detach.base.nm_so; 629 struct inpcb *inp; 630 int error; 631 632 inp = so->so_pcb; 633 if (inp) { 634 in6_pcbdetach(inp); 635 error = 0; 636 } else { 637 error = EINVAL; 638 } 639 lwkt_replymsg(&msg->detach.base.lmsg, error); 640 } 641 642 static void 643 udp6_disconnect(netmsg_t msg) 644 { 645 struct socket *so = msg->disconnect.base.nm_so; 646 struct inpcb *inp; 647 int error; 648 649 inp = so->so_pcb; 650 if (inp == NULL) { 651 error = EINVAL; 652 goto out; 653 } 654 655 if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { 656 error = ENOTCONN; 657 } else { 658 in6_pcbdisconnect(inp); 659 soclrstate(so, SS_ISCONNECTED); /* XXX */ 660 error = 0; 661 } 662 out: 663 lwkt_replymsg(&msg->disconnect.base.lmsg, error); 664 } 665 666 static void 667 udp6_send(netmsg_t msg) 668 { 669 struct socket *so = msg->send.base.nm_so; 670 struct mbuf *m = msg->send.nm_m; 671 struct sockaddr *addr = msg->send.nm_addr; 672 struct mbuf *control = msg->send.nm_control; 673 struct thread *td = msg->send.nm_td; 674 struct inpcb *inp; 675 int error = 0; 676 677 inp = so->so_pcb; 678 if (inp == NULL) { 679 error = EINVAL; 680 goto bad; 681 } 682 683 if (addr) { 684 struct sockaddr_in6 *sin6; 685 686 if (addr->sa_len != sizeof(struct sockaddr_in6)) { 687 error = EINVAL; 688 goto bad; 689 } 690 if (addr->sa_family != AF_INET6) { 691 error = EAFNOSUPPORT; 692 goto bad; 693 } 694 695 sin6 = (struct sockaddr_in6 *)addr; 696 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 697 error = EADDRNOTAVAIL; 698 goto bad; 699 } 700 } 701 702 error = udp6_output(inp, m, addr, control, td); 703 lwkt_replymsg(&msg->send.base.lmsg, error); 704 return; 705 bad: 706 m_freem(m); 707 lwkt_replymsg(&msg->send.base.lmsg, error); 708 } 709 710 struct pr_usrreqs udp6_usrreqs = { 711 .pru_abort = udp6_abort, 712 .pru_accept = pr_generic_notsupp, 713 .pru_attach = udp6_attach, 714 .pru_bind = udp6_bind, 715 .pru_connect = udp6_connect, 716 .pru_connect2 = pr_generic_notsupp, 717 .pru_control = in6_control_dispatch, 718 .pru_detach = udp6_detach, 719 .pru_disconnect = udp6_disconnect, 720 .pru_listen = pr_generic_notsupp, 721 .pru_peeraddr = in6_setpeeraddr_dispatch, 722 .pru_rcvd = pr_generic_notsupp, 723 .pru_rcvoob = pr_generic_notsupp, 724 .pru_send = udp6_send, 725 .pru_sense = pru_sense_null, 726 .pru_shutdown = udp_shutdown, 727 .pru_sockaddr = in6_setsockaddr_dispatch, 728 .pru_sosend = sosend, 729 .pru_soreceive = soreceive 730 }; 731 732