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