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