1 /* $NetBSD: uipc_usrreq.c,v 1.23 1996/05/23 17:07:03 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/proc.h> 41 #include <sys/filedesc.h> 42 #include <sys/domain.h> 43 #include <sys/protosw.h> 44 #include <sys/socket.h> 45 #include <sys/socketvar.h> 46 #include <sys/unpcb.h> 47 #include <sys/un.h> 48 #include <sys/namei.h> 49 #include <sys/vnode.h> 50 #include <sys/file.h> 51 #include <sys/stat.h> 52 #include <sys/mbuf.h> 53 54 /* 55 * Unix communications domain. 56 * 57 * TODO: 58 * SEQPACKET, RDM 59 * rethink name space problems 60 * need a proper out-of-band 61 */ 62 struct sockaddr_un sun_noname = { sizeof(sun_noname), AF_UNIX }; 63 ino_t unp_ino; /* prototype for fake inode numbers */ 64 65 int 66 unp_output(m, control, unp) 67 struct mbuf *m, *control; 68 struct unpcb *unp; 69 { 70 struct socket *so2; 71 struct sockaddr_un *sun; 72 73 so2 = unp->unp_conn->unp_socket; 74 if (unp->unp_addr) 75 sun = unp->unp_addr; 76 else 77 sun = &sun_noname; 78 if (sbappendaddr(&so2->so_rcv, (struct sockaddr *)sun, m, 79 control) == 0) { 80 m_freem(control); 81 m_freem(m); 82 return (EINVAL); 83 } else { 84 sorwakeup(so2); 85 return (0); 86 } 87 } 88 89 void 90 unp_setsockaddr(unp, nam) 91 register struct unpcb *unp; 92 struct mbuf *nam; 93 { 94 struct sockaddr_un *sun; 95 96 if (unp->unp_addr) 97 sun = unp->unp_addr; 98 else 99 sun = &sun_noname; 100 nam->m_len = sun->sun_len; 101 bcopy(sun, mtod(nam, caddr_t), (size_t)nam->m_len); 102 } 103 104 void 105 unp_setpeeraddr(unp, nam) 106 register struct unpcb *unp; 107 struct mbuf *nam; 108 { 109 struct sockaddr_un *sun; 110 111 if (unp->unp_conn && unp->unp_conn->unp_addr) 112 sun = unp->unp_conn->unp_addr; 113 else 114 sun = &sun_noname; 115 nam->m_len = sun->sun_len; 116 bcopy(sun, mtod(nam, caddr_t), (size_t)nam->m_len); 117 } 118 119 /*ARGSUSED*/ 120 int 121 uipc_usrreq(so, req, m, nam, control, p) 122 struct socket *so; 123 int req; 124 struct mbuf *m, *nam, *control; 125 struct proc *p; 126 { 127 struct unpcb *unp = sotounpcb(so); 128 register struct socket *so2; 129 register int error = 0; 130 131 if (req == PRU_CONTROL) 132 return (EOPNOTSUPP); 133 134 #ifdef DIAGNOSTIC 135 if (req != PRU_SEND && req != PRU_SENDOOB && control) 136 panic("uipc_usrreq: unexpected control mbuf"); 137 #endif 138 if (unp == 0 && req != PRU_ATTACH) { 139 error = EINVAL; 140 goto release; 141 } 142 143 switch (req) { 144 145 case PRU_ATTACH: 146 if (unp != 0) { 147 error = EISCONN; 148 break; 149 } 150 error = unp_attach(so); 151 break; 152 153 case PRU_DETACH: 154 unp_detach(unp); 155 break; 156 157 case PRU_BIND: 158 error = unp_bind(unp, nam, p); 159 break; 160 161 case PRU_LISTEN: 162 if (unp->unp_vnode == 0) 163 error = EINVAL; 164 break; 165 166 case PRU_CONNECT: 167 error = unp_connect(so, nam, p); 168 break; 169 170 case PRU_CONNECT2: 171 error = unp_connect2(so, (struct socket *)nam); 172 break; 173 174 case PRU_DISCONNECT: 175 unp_disconnect(unp); 176 break; 177 178 case PRU_ACCEPT: 179 unp_setpeeraddr(unp, nam); 180 break; 181 182 case PRU_SHUTDOWN: 183 socantsendmore(so); 184 unp_shutdown(unp); 185 break; 186 187 case PRU_RCVD: 188 switch (so->so_type) { 189 190 case SOCK_DGRAM: 191 panic("uipc 1"); 192 /*NOTREACHED*/ 193 194 case SOCK_STREAM: 195 #define rcv (&so->so_rcv) 196 #define snd (&so2->so_snd) 197 if (unp->unp_conn == 0) 198 break; 199 so2 = unp->unp_conn->unp_socket; 200 /* 201 * Adjust backpressure on sender 202 * and wakeup any waiting to write. 203 */ 204 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 205 unp->unp_mbcnt = rcv->sb_mbcnt; 206 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 207 unp->unp_cc = rcv->sb_cc; 208 sowwakeup(so2); 209 #undef snd 210 #undef rcv 211 break; 212 213 default: 214 panic("uipc 2"); 215 } 216 break; 217 218 case PRU_SEND: 219 if (control && (error = unp_internalize(control, p))) 220 break; 221 switch (so->so_type) { 222 223 case SOCK_DGRAM: { 224 if (nam) { 225 if ((so->so_state & SS_ISCONNECTED) != 0) { 226 error = EISCONN; 227 goto die; 228 } 229 error = unp_connect(so, nam, p); 230 if (error) { 231 die: 232 m_freem(control); 233 m_freem(m); 234 break; 235 } 236 } else { 237 if ((so->so_state & SS_ISCONNECTED) == 0) { 238 error = ENOTCONN; 239 goto die; 240 } 241 } 242 error = unp_output(m, control, unp); 243 if (nam) 244 unp_disconnect(unp); 245 break; 246 } 247 248 case SOCK_STREAM: 249 #define rcv (&so2->so_rcv) 250 #define snd (&so->so_snd) 251 if (unp->unp_conn == 0) 252 panic("uipc 3"); 253 so2 = unp->unp_conn->unp_socket; 254 /* 255 * Send to paired receive port, and then reduce 256 * send buffer hiwater marks to maintain backpressure. 257 * Wake up readers. 258 */ 259 if (control) { 260 if (sbappendcontrol(rcv, m, control) == 0) 261 m_freem(control); 262 } else 263 sbappend(rcv, m); 264 snd->sb_mbmax -= 265 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 266 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 267 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 268 unp->unp_conn->unp_cc = rcv->sb_cc; 269 sorwakeup(so2); 270 #undef snd 271 #undef rcv 272 break; 273 274 default: 275 panic("uipc 4"); 276 } 277 break; 278 279 case PRU_ABORT: 280 unp_drop(unp, ECONNABORTED); 281 break; 282 283 case PRU_SENSE: 284 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 285 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 286 so2 = unp->unp_conn->unp_socket; 287 ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 288 } 289 ((struct stat *) m)->st_dev = NODEV; 290 if (unp->unp_ino == 0) 291 unp->unp_ino = unp_ino++; 292 ((struct stat *) m)->st_ino = unp->unp_ino; 293 return (0); 294 295 case PRU_RCVOOB: 296 error = EOPNOTSUPP; 297 break; 298 299 case PRU_SENDOOB: 300 m_freem(control); 301 m_freem(m); 302 error = EOPNOTSUPP; 303 break; 304 305 case PRU_SOCKADDR: 306 unp_setsockaddr(unp, nam); 307 break; 308 309 case PRU_PEERADDR: 310 unp_setpeeraddr(unp, nam); 311 break; 312 313 default: 314 panic("piusrreq"); 315 } 316 317 release: 318 return (error); 319 } 320 321 /* 322 * Both send and receive buffers are allocated PIPSIZ bytes of buffering 323 * for stream sockets, although the total for sender and receiver is 324 * actually only PIPSIZ. 325 * Datagram sockets really use the sendspace as the maximum datagram size, 326 * and don't really want to reserve the sendspace. Their recvspace should 327 * be large enough for at least one max-size datagram plus address. 328 */ 329 #define PIPSIZ 4096 330 u_long unpst_sendspace = PIPSIZ; 331 u_long unpst_recvspace = PIPSIZ; 332 u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 333 u_long unpdg_recvspace = 4*1024; 334 335 int unp_rights; /* file descriptors in flight */ 336 337 int 338 unp_attach(so) 339 struct socket *so; 340 { 341 register struct unpcb *unp; 342 int error; 343 344 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 345 switch (so->so_type) { 346 347 case SOCK_STREAM: 348 error = soreserve(so, unpst_sendspace, unpst_recvspace); 349 break; 350 351 case SOCK_DGRAM: 352 error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 353 break; 354 355 default: 356 panic("unp_attach"); 357 } 358 if (error) 359 return (error); 360 } 361 unp = malloc(sizeof(*unp), M_PCB, M_NOWAIT); 362 if (unp == NULL) 363 return (ENOBUFS); 364 bzero((caddr_t)unp, sizeof(*unp)); 365 unp->unp_socket = so; 366 so->so_pcb = unp; 367 return (0); 368 } 369 370 void 371 unp_detach(unp) 372 register struct unpcb *unp; 373 { 374 375 if (unp->unp_vnode) { 376 unp->unp_vnode->v_socket = 0; 377 vrele(unp->unp_vnode); 378 unp->unp_vnode = 0; 379 } 380 if (unp->unp_conn) 381 unp_disconnect(unp); 382 while (unp->unp_refs) 383 unp_drop(unp->unp_refs, ECONNRESET); 384 soisdisconnected(unp->unp_socket); 385 unp->unp_socket->so_pcb = 0; 386 if (unp->unp_addr) 387 m_freem(dtom(unp->unp_addr)); 388 if (unp_rights) { 389 /* 390 * Normally the receive buffer is flushed later, 391 * in sofree, but if our receive buffer holds references 392 * to descriptors that are now garbage, we will dispose 393 * of those descriptor references after the garbage collector 394 * gets them (resulting in a "panic: closef: count < 0"). 395 */ 396 sorflush(unp->unp_socket); 397 free(unp, M_PCB); 398 unp_gc(); 399 } else 400 free(unp, M_PCB); 401 } 402 403 int 404 unp_bind(unp, nam, p) 405 struct unpcb *unp; 406 struct mbuf *nam; 407 struct proc *p; 408 { 409 struct sockaddr_un *sun = mtod(nam, struct sockaddr_un *); 410 register struct vnode *vp; 411 struct vattr vattr; 412 int error; 413 struct nameidata nd; 414 415 if (unp->unp_vnode != 0) 416 return (EINVAL); 417 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, 418 sun->sun_path, p); 419 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 420 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 421 return (EINVAL); 422 } else 423 *(mtod(nam, caddr_t) + nam->m_len) = 0; 424 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 425 if ((error = namei(&nd)) != 0) 426 return (error); 427 vp = nd.ni_vp; 428 if (vp != NULL) { 429 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 430 if (nd.ni_dvp == vp) 431 vrele(nd.ni_dvp); 432 else 433 vput(nd.ni_dvp); 434 vrele(vp); 435 return (EADDRINUSE); 436 } 437 VATTR_NULL(&vattr); 438 vattr.va_type = VSOCK; 439 vattr.va_mode = ACCESSPERMS; 440 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 441 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 442 if (error) 443 return (error); 444 vp = nd.ni_vp; 445 vp->v_socket = unp->unp_socket; 446 unp->unp_vnode = vp; 447 unp->unp_addr = 448 mtod(m_copy(nam, 0, (int)M_COPYALL), struct sockaddr_un *); 449 VOP_UNLOCK(vp); 450 return (0); 451 } 452 453 int 454 unp_connect(so, nam, p) 455 struct socket *so; 456 struct mbuf *nam; 457 struct proc *p; 458 { 459 register struct sockaddr_un *sun = mtod(nam, struct sockaddr_un *); 460 register struct vnode *vp; 461 register struct socket *so2, *so3; 462 struct unpcb *unp2, *unp3; 463 int error; 464 struct nameidata nd; 465 466 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, sun->sun_path, p); 467 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 468 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 469 return (EINVAL); 470 } else 471 *(mtod(nam, caddr_t) + nam->m_len) = 0; 472 if ((error = namei(&nd)) != 0) 473 return (error); 474 vp = nd.ni_vp; 475 if (vp->v_type != VSOCK) { 476 error = ENOTSOCK; 477 goto bad; 478 } 479 if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) != 0) 480 goto bad; 481 so2 = vp->v_socket; 482 if (so2 == 0) { 483 error = ECONNREFUSED; 484 goto bad; 485 } 486 if (so->so_type != so2->so_type) { 487 error = EPROTOTYPE; 488 goto bad; 489 } 490 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 491 if ((so2->so_options & SO_ACCEPTCONN) == 0 || 492 (so3 = sonewconn(so2, 0)) == 0) { 493 error = ECONNREFUSED; 494 goto bad; 495 } 496 unp2 = sotounpcb(so2); 497 unp3 = sotounpcb(so3); 498 if (unp2->unp_addr) 499 unp3->unp_addr = mtod(m_copy(dtom(unp2->unp_addr), 0, 500 (int)M_COPYALL), struct sockaddr_un *); 501 so2 = so3; 502 } 503 error = unp_connect2(so, so2); 504 bad: 505 vput(vp); 506 return (error); 507 } 508 509 int 510 unp_connect2(so, so2) 511 register struct socket *so; 512 register struct socket *so2; 513 { 514 register struct unpcb *unp = sotounpcb(so); 515 register struct unpcb *unp2; 516 517 if (so2->so_type != so->so_type) 518 return (EPROTOTYPE); 519 unp2 = sotounpcb(so2); 520 unp->unp_conn = unp2; 521 switch (so->so_type) { 522 523 case SOCK_DGRAM: 524 unp->unp_nextref = unp2->unp_refs; 525 unp2->unp_refs = unp; 526 soisconnected(so); 527 break; 528 529 case SOCK_STREAM: 530 unp2->unp_conn = unp; 531 soisconnected(so); 532 soisconnected(so2); 533 break; 534 535 default: 536 panic("unp_connect2"); 537 } 538 return (0); 539 } 540 541 void 542 unp_disconnect(unp) 543 struct unpcb *unp; 544 { 545 register struct unpcb *unp2 = unp->unp_conn; 546 547 if (unp2 == 0) 548 return; 549 unp->unp_conn = 0; 550 switch (unp->unp_socket->so_type) { 551 552 case SOCK_DGRAM: 553 if (unp2->unp_refs == unp) 554 unp2->unp_refs = unp->unp_nextref; 555 else { 556 unp2 = unp2->unp_refs; 557 for (;;) { 558 if (unp2 == 0) 559 panic("unp_disconnect"); 560 if (unp2->unp_nextref == unp) 561 break; 562 unp2 = unp2->unp_nextref; 563 } 564 unp2->unp_nextref = unp->unp_nextref; 565 } 566 unp->unp_nextref = 0; 567 unp->unp_socket->so_state &= ~SS_ISCONNECTED; 568 break; 569 570 case SOCK_STREAM: 571 soisdisconnected(unp->unp_socket); 572 unp2->unp_conn = 0; 573 soisdisconnected(unp2->unp_socket); 574 break; 575 } 576 } 577 578 #ifdef notdef 579 unp_abort(unp) 580 struct unpcb *unp; 581 { 582 583 unp_detach(unp); 584 } 585 #endif 586 587 void 588 unp_shutdown(unp) 589 struct unpcb *unp; 590 { 591 struct socket *so; 592 593 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 594 (so = unp->unp_conn->unp_socket)) 595 socantrcvmore(so); 596 } 597 598 void 599 unp_drop(unp, errno) 600 struct unpcb *unp; 601 int errno; 602 { 603 struct socket *so = unp->unp_socket; 604 605 so->so_error = errno; 606 unp_disconnect(unp); 607 if (so->so_head) { 608 so->so_pcb = 0; 609 sofree(so); 610 if (unp->unp_addr) 611 m_freem(dtom(unp->unp_addr)); 612 free(unp, M_PCB); 613 } 614 } 615 616 #ifdef notdef 617 unp_drain() 618 { 619 620 } 621 #endif 622 623 int 624 unp_externalize(rights) 625 struct mbuf *rights; 626 { 627 struct proc *p = curproc; /* XXX */ 628 register int i; 629 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 630 register struct file **rp = (struct file **)(cm + 1); 631 register struct file *fp; 632 int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 633 int f; 634 635 if (!fdavail(p, newfds)) { 636 for (i = 0; i < newfds; i++) { 637 fp = *rp; 638 unp_discard(fp); 639 *rp++ = 0; 640 } 641 return (EMSGSIZE); 642 } 643 for (i = 0; i < newfds; i++) { 644 if (fdalloc(p, 0, &f)) 645 panic("unp_externalize"); 646 fp = *rp; 647 p->p_fd->fd_ofiles[f] = fp; 648 fp->f_msgcount--; 649 unp_rights--; 650 *(int *)rp++ = f; 651 } 652 return (0); 653 } 654 655 int 656 unp_internalize(control, p) 657 struct mbuf *control; 658 struct proc *p; 659 { 660 struct filedesc *fdp = p->p_fd; 661 register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 662 register struct file **rp; 663 register struct file *fp; 664 register int i, fd; 665 int oldfds; 666 667 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 668 cm->cmsg_len != control->m_len) 669 return (EINVAL); 670 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 671 rp = (struct file **)(cm + 1); 672 for (i = 0; i < oldfds; i++) { 673 fd = *(int *)rp++; 674 if ((unsigned)fd >= fdp->fd_nfiles || 675 fdp->fd_ofiles[fd] == NULL) 676 return (EBADF); 677 } 678 rp = (struct file **)(cm + 1); 679 for (i = 0; i < oldfds; i++) { 680 fp = fdp->fd_ofiles[*(int *)rp]; 681 *rp++ = fp; 682 fp->f_count++; 683 fp->f_msgcount++; 684 unp_rights++; 685 } 686 return (0); 687 } 688 689 int unp_defer, unp_gcing; 690 extern struct domain unixdomain; 691 692 void 693 unp_gc() 694 { 695 register struct file *fp, *nextfp; 696 register struct socket *so; 697 struct file **extra_ref, **fpp; 698 int nunref, i; 699 700 if (unp_gcing) 701 return; 702 unp_gcing = 1; 703 unp_defer = 0; 704 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) 705 fp->f_flag &= ~(FMARK|FDEFER); 706 do { 707 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 708 if (fp->f_count == 0) 709 continue; 710 if (fp->f_flag & FDEFER) { 711 fp->f_flag &= ~FDEFER; 712 unp_defer--; 713 } else { 714 if (fp->f_flag & FMARK) 715 continue; 716 if (fp->f_count == fp->f_msgcount) 717 continue; 718 fp->f_flag |= FMARK; 719 } 720 if (fp->f_type != DTYPE_SOCKET || 721 (so = (struct socket *)fp->f_data) == 0) 722 continue; 723 if (so->so_proto->pr_domain != &unixdomain || 724 (so->so_proto->pr_flags&PR_RIGHTS) == 0) 725 continue; 726 #ifdef notdef 727 if (so->so_rcv.sb_flags & SB_LOCK) { 728 /* 729 * This is problematical; it's not clear 730 * we need to wait for the sockbuf to be 731 * unlocked (on a uniprocessor, at least), 732 * and it's also not clear what to do 733 * if sbwait returns an error due to receipt 734 * of a signal. If sbwait does return 735 * an error, we'll go into an infinite 736 * loop. Delete all of this for now. 737 */ 738 (void) sbwait(&so->so_rcv); 739 goto restart; 740 } 741 #endif 742 unp_scan(so->so_rcv.sb_mb, unp_mark); 743 } 744 } while (unp_defer); 745 /* 746 * We grab an extra reference to each of the file table entries 747 * that are not otherwise accessible and then free the rights 748 * that are stored in messages on them. 749 * 750 * The bug in the orginal code is a little tricky, so I'll describe 751 * what's wrong with it here. 752 * 753 * It is incorrect to simply unp_discard each entry for f_msgcount 754 * times -- consider the case of sockets A and B that contain 755 * references to each other. On a last close of some other socket, 756 * we trigger a gc since the number of outstanding rights (unp_rights) 757 * is non-zero. If during the sweep phase the gc code un_discards, 758 * we end up doing a (full) closef on the descriptor. A closef on A 759 * results in the following chain. Closef calls soo_close, which 760 * calls soclose. Soclose calls first (through the switch 761 * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 762 * returns because the previous instance had set unp_gcing, and 763 * we return all the way back to soclose, which marks the socket 764 * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 765 * to free up the rights that are queued in messages on the socket A, 766 * i.e., the reference on B. The sorflush calls via the dom_dispose 767 * switch unp_dispose, which unp_scans with unp_discard. This second 768 * instance of unp_discard just calls closef on B. 769 * 770 * Well, a similar chain occurs on B, resulting in a sorflush on B, 771 * which results in another closef on A. Unfortunately, A is already 772 * being closed, and the descriptor has already been marked with 773 * SS_NOFDREF, and soclose panics at this point. 774 * 775 * Here, we first take an extra reference to each inaccessible 776 * descriptor. Then, we call sorflush ourself, since we know 777 * it is a Unix domain socket anyhow. After we destroy all the 778 * rights carried in messages, we do a last closef to get rid 779 * of our extra reference. This is the last close, and the 780 * unp_detach etc will shut down the socket. 781 * 782 * 91/09/19, bsy@cs.cmu.edu 783 */ 784 extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); 785 for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0; 786 fp = nextfp) { 787 nextfp = fp->f_list.le_next; 788 if (fp->f_count == 0) 789 continue; 790 if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { 791 *fpp++ = fp; 792 nunref++; 793 fp->f_count++; 794 } 795 } 796 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 797 sorflush((struct socket *)(*fpp)->f_data); 798 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 799 (void) closef(*fpp, (struct proc *)0); 800 free((caddr_t)extra_ref, M_FILE); 801 unp_gcing = 0; 802 } 803 804 void 805 unp_dispose(m) 806 struct mbuf *m; 807 { 808 809 if (m) 810 unp_scan(m, unp_discard); 811 } 812 813 void 814 unp_scan(m0, op) 815 register struct mbuf *m0; 816 void (*op) __P((struct file *)); 817 { 818 register struct mbuf *m; 819 register struct file **rp; 820 register struct cmsghdr *cm; 821 register int i; 822 int qfds; 823 824 while (m0) { 825 for (m = m0; m; m = m->m_next) 826 if (m->m_type == MT_CONTROL && 827 m->m_len >= sizeof(*cm)) { 828 cm = mtod(m, struct cmsghdr *); 829 if (cm->cmsg_level != SOL_SOCKET || 830 cm->cmsg_type != SCM_RIGHTS) 831 continue; 832 qfds = (cm->cmsg_len - sizeof *cm) 833 / sizeof (struct file *); 834 rp = (struct file **)(cm + 1); 835 for (i = 0; i < qfds; i++) 836 (*op)(*rp++); 837 break; /* XXX, but saves time */ 838 } 839 m0 = m0->m_act; 840 } 841 } 842 843 void 844 unp_mark(fp) 845 struct file *fp; 846 { 847 848 if (fp->f_flag & FMARK) 849 return; 850 unp_defer++; 851 fp->f_flag |= (FMARK|FDEFER); 852 } 853 854 void 855 unp_discard(fp) 856 struct file *fp; 857 { 858 859 fp->f_msgcount--; 860 unp_rights--; 861 (void) closef(fp, (struct proc *)0); 862 } 863