|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1989, 1991, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 ! 55: */ ! 56: ! 57: #include <sys/param.h> ! 58: #include <sys/systm.h> ! 59: #include <sys/kernel.h> ! 60: #include <sys/domain.h> ! 61: #include <sys/fcntl.h> ! 62: #include <sys/malloc.h> /* XXX must be before <sys/file.h> */ ! 63: #include <sys/file.h> ! 64: #include <sys/filedesc.h> ! 65: #include <sys/lock.h> ! 66: #include <sys/mbuf.h> ! 67: #include <sys/namei.h> ! 68: #include <sys/proc.h> ! 69: #include <sys/protosw.h> ! 70: #include <sys/socket.h> ! 71: #include <sys/socketvar.h> ! 72: #include <sys/stat.h> ! 73: #include <sys/sysctl.h> ! 74: #include <sys/un.h> ! 75: #include <sys/unpcb.h> ! 76: #include <sys/vnode.h> ! 77: ! 78: #include <kern/zalloc.h> ! 79: ! 80: struct zone *unp_zone; ! 81: static unp_gen_t unp_gencnt; ! 82: static u_int unp_count; ! 83: ! 84: static struct unp_head unp_shead, unp_dhead; ! 85: ! 86: /* ! 87: * Unix communications domain. ! 88: * ! 89: * TODO: ! 90: * SEQPACKET, RDM ! 91: * rethink name space problems ! 92: * need a proper out-of-band ! 93: * lock pushdown ! 94: */ ! 95: static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; ! 96: static ino_t unp_ino; /* prototype for fake inode numbers */ ! 97: ! 98: static int unp_attach __P((struct socket *)); ! 99: static void unp_detach __P((struct unpcb *)); ! 100: static int unp_bind __P((struct unpcb *,struct sockaddr *, struct proc *)); ! 101: static int unp_connect __P((struct socket *,struct sockaddr *, ! 102: struct proc *)); ! 103: static void unp_disconnect __P((struct unpcb *)); ! 104: static void unp_shutdown __P((struct unpcb *)); ! 105: static void unp_drop __P((struct unpcb *, int)); ! 106: static void unp_gc __P((void)); ! 107: static void unp_scan __P((struct mbuf *, void (*)(struct file *))); ! 108: static void unp_mark __P((struct file *)); ! 109: static void unp_discard __P((struct file *)); ! 110: static int unp_internalize __P((struct mbuf *, struct proc *)); ! 111: ! 112: static int ! 113: uipc_abort(struct socket *so) ! 114: { ! 115: struct unpcb *unp = sotounpcb(so); ! 116: ! 117: if (unp == 0) ! 118: return EINVAL; ! 119: unp_drop(unp, ECONNABORTED); ! 120: return 0; ! 121: } ! 122: ! 123: static int ! 124: uipc_accept(struct socket *so, struct sockaddr **nam) ! 125: { ! 126: struct unpcb *unp = sotounpcb(so); ! 127: ! 128: if (unp == 0) ! 129: return EINVAL; ! 130: ! 131: /* ! 132: * Pass back name of connected socket, ! 133: * if it was bound and we are still connected ! 134: * (our peer may have closed already!). ! 135: */ ! 136: if (unp->unp_conn && unp->unp_conn->unp_addr) { ! 137: *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, ! 138: 1); ! 139: } else { ! 140: *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); ! 141: } ! 142: return 0; ! 143: } ! 144: ! 145: static int ! 146: uipc_attach(struct socket *so, int proto, struct proc *p) ! 147: { ! 148: struct unpcb *unp = sotounpcb(so); ! 149: ! 150: if (unp != 0) ! 151: return EISCONN; ! 152: return unp_attach(so); ! 153: } ! 154: ! 155: static int ! 156: uipc_bind(struct socket *so, struct sockaddr *nam, struct proc *p) ! 157: { ! 158: struct unpcb *unp = sotounpcb(so); ! 159: ! 160: if (unp == 0) ! 161: return EINVAL; ! 162: ! 163: return unp_bind(unp, nam, p); ! 164: } ! 165: ! 166: static int ! 167: uipc_connect(struct socket *so, struct sockaddr *nam, struct proc *p) ! 168: { ! 169: struct unpcb *unp = sotounpcb(so); ! 170: ! 171: if (unp == 0) ! 172: return EINVAL; ! 173: return unp_connect(so, nam, p); ! 174: } ! 175: ! 176: static int ! 177: uipc_connect2(struct socket *so1, struct socket *so2) ! 178: { ! 179: struct unpcb *unp = sotounpcb(so1); ! 180: ! 181: if (unp == 0) ! 182: return EINVAL; ! 183: ! 184: return unp_connect2(so1, so2); ! 185: } ! 186: ! 187: /* control is EOPNOTSUPP */ ! 188: ! 189: static int ! 190: uipc_detach(struct socket *so) ! 191: { ! 192: struct unpcb *unp = sotounpcb(so); ! 193: ! 194: if (unp == 0) ! 195: return EINVAL; ! 196: ! 197: unp_detach(unp); ! 198: return 0; ! 199: } ! 200: ! 201: static int ! 202: uipc_disconnect(struct socket *so) ! 203: { ! 204: struct unpcb *unp = sotounpcb(so); ! 205: ! 206: if (unp == 0) ! 207: return EINVAL; ! 208: unp_disconnect(unp); ! 209: return 0; ! 210: } ! 211: ! 212: static int ! 213: uipc_listen(struct socket *so, struct proc *p) ! 214: { ! 215: struct unpcb *unp = sotounpcb(so); ! 216: ! 217: if (unp == 0 || unp->unp_vnode == 0) ! 218: return EINVAL; ! 219: return 0; ! 220: } ! 221: ! 222: static int ! 223: uipc_peeraddr(struct socket *so, struct sockaddr **nam) ! 224: { ! 225: struct unpcb *unp = sotounpcb(so); ! 226: ! 227: if (unp == 0) ! 228: return EINVAL; ! 229: if (unp->unp_conn && unp->unp_conn->unp_addr) ! 230: *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, ! 231: 1); ! 232: return 0; ! 233: } ! 234: ! 235: static int ! 236: uipc_rcvd(struct socket *so, int flags) ! 237: { ! 238: struct unpcb *unp = sotounpcb(so); ! 239: struct socket *so2; ! 240: ! 241: if (unp == 0) ! 242: return EINVAL; ! 243: switch (so->so_type) { ! 244: case SOCK_DGRAM: ! 245: panic("uipc_rcvd DGRAM?"); ! 246: /*NOTREACHED*/ ! 247: ! 248: case SOCK_STREAM: ! 249: #define rcv (&so->so_rcv) ! 250: #define snd (&so2->so_snd) ! 251: if (unp->unp_conn == 0) ! 252: break; ! 253: so2 = unp->unp_conn->unp_socket; ! 254: /* ! 255: * Adjust backpressure on sender ! 256: * and wakeup any waiting to write. ! 257: */ ! 258: snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; ! 259: unp->unp_mbcnt = rcv->sb_mbcnt; ! 260: snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; ! 261: unp->unp_cc = rcv->sb_cc; ! 262: sowwakeup(so2); ! 263: #undef snd ! 264: #undef rcv ! 265: break; ! 266: ! 267: default: ! 268: panic("uipc_rcvd unknown socktype"); ! 269: } ! 270: return 0; ! 271: } ! 272: ! 273: /* pru_rcvoob is EOPNOTSUPP */ ! 274: ! 275: static int ! 276: uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, ! 277: struct mbuf *control, struct proc *p) ! 278: { ! 279: int error = 0; ! 280: struct unpcb *unp = sotounpcb(so); ! 281: struct socket *so2; ! 282: ! 283: if (unp == 0) { ! 284: error = EINVAL; ! 285: goto release; ! 286: } ! 287: if (flags & PRUS_OOB) { ! 288: error = EOPNOTSUPP; ! 289: goto release; ! 290: } ! 291: ! 292: if (control && (error = unp_internalize(control, p))) ! 293: goto release; ! 294: ! 295: switch (so->so_type) { ! 296: case SOCK_DGRAM: ! 297: { ! 298: struct sockaddr *from; ! 299: ! 300: if (nam) { ! 301: if (unp->unp_conn) { ! 302: error = EISCONN; ! 303: break; ! 304: } ! 305: error = unp_connect(so, nam, p); ! 306: if (error) ! 307: break; ! 308: } else { ! 309: if (unp->unp_conn == 0) { ! 310: error = ENOTCONN; ! 311: break; ! 312: } ! 313: } ! 314: so2 = unp->unp_conn->unp_socket; ! 315: if (unp->unp_addr) ! 316: from = (struct sockaddr *)unp->unp_addr; ! 317: else ! 318: from = &sun_noname; ! 319: if (sbappendaddr(&so2->so_rcv, from, m, control)) { ! 320: sorwakeup(so2); ! 321: m = 0; ! 322: control = 0; ! 323: } else ! 324: error = ENOBUFS; ! 325: if (nam) ! 326: unp_disconnect(unp); ! 327: break; ! 328: } ! 329: ! 330: case SOCK_STREAM: ! 331: #define rcv (&so2->so_rcv) ! 332: #define snd (&so->so_snd) ! 333: /* Connect if not connected yet. */ ! 334: /* ! 335: * Note: A better implementation would complain ! 336: * if not equal to the peer's address. ! 337: */ ! 338: if ((so->so_state & SS_ISCONNECTED) == 0) { ! 339: if (nam) { ! 340: error = unp_connect(so, nam, p); ! 341: if (error) ! 342: break; /* XXX */ ! 343: } else { ! 344: error = ENOTCONN; ! 345: break; ! 346: } ! 347: } ! 348: ! 349: if (so->so_state & SS_CANTSENDMORE) { ! 350: error = EPIPE; ! 351: break; ! 352: } ! 353: if (unp->unp_conn == 0) ! 354: panic("uipc_send connected but no connection?"); ! 355: so2 = unp->unp_conn->unp_socket; ! 356: /* ! 357: * Send to paired receive port, and then reduce ! 358: * send buffer hiwater marks to maintain backpressure. ! 359: * Wake up readers. ! 360: */ ! 361: if (control) { ! 362: if (sbappendcontrol(rcv, m, control)) ! 363: control = 0; ! 364: } else ! 365: sbappend(rcv, m); ! 366: snd->sb_mbmax -= ! 367: rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; ! 368: unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; ! 369: snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; ! 370: unp->unp_conn->unp_cc = rcv->sb_cc; ! 371: sorwakeup(so2); ! 372: m = 0; ! 373: #undef snd ! 374: #undef rcv ! 375: break; ! 376: ! 377: default: ! 378: panic("uipc_send unknown socktype"); ! 379: } ! 380: ! 381: /* ! 382: * SEND_EOF is equivalent to a SEND followed by ! 383: * a SHUTDOWN. ! 384: */ ! 385: if (flags & PRUS_EOF) { ! 386: socantsendmore(so); ! 387: unp_shutdown(unp); ! 388: } ! 389: ! 390: release: ! 391: if (control) ! 392: m_freem(control); ! 393: if (m) ! 394: m_freem(m); ! 395: return error; ! 396: } ! 397: ! 398: static int ! 399: uipc_sense(struct socket *so, struct stat *sb) ! 400: { ! 401: struct unpcb *unp = sotounpcb(so); ! 402: struct socket *so2; ! 403: ! 404: if (unp == 0) ! 405: return EINVAL; ! 406: sb->st_blksize = so->so_snd.sb_hiwat; ! 407: if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { ! 408: so2 = unp->unp_conn->unp_socket; ! 409: sb->st_blksize += so2->so_rcv.sb_cc; ! 410: } ! 411: sb->st_dev = NODEV; ! 412: if (unp->unp_ino == 0) ! 413: unp->unp_ino = unp_ino++; ! 414: sb->st_ino = unp->unp_ino; ! 415: return (0); ! 416: } ! 417: ! 418: static int ! 419: uipc_shutdown(struct socket *so) ! 420: { ! 421: struct unpcb *unp = sotounpcb(so); ! 422: ! 423: if (unp == 0) ! 424: return EINVAL; ! 425: socantsendmore(so); ! 426: unp_shutdown(unp); ! 427: return 0; ! 428: } ! 429: ! 430: static int ! 431: uipc_sockaddr(struct socket *so, struct sockaddr **nam) ! 432: { ! 433: struct unpcb *unp = sotounpcb(so); ! 434: ! 435: if (unp == 0) ! 436: return EINVAL; ! 437: if (unp->unp_addr) ! 438: *nam = dup_sockaddr((struct sockaddr *)unp->unp_addr, 1); ! 439: return 0; ! 440: } ! 441: ! 442: struct pr_usrreqs uipc_usrreqs = { ! 443: uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect, ! 444: uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect, ! 445: uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp, ! 446: uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr, ! 447: sosend, soreceive, sopoll ! 448: }; ! 449: ! 450: /* ! 451: * Both send and receive buffers are allocated PIPSIZ bytes of buffering ! 452: * for stream sockets, although the total for sender and receiver is ! 453: * actually only PIPSIZ. ! 454: * Datagram sockets really use the sendspace as the maximum datagram size, ! 455: * and don't really want to reserve the sendspace. Their recvspace should ! 456: * be large enough for at least one max-size datagram plus address. ! 457: */ ! 458: #ifndef PIPSIZ ! 459: #define PIPSIZ 8192 ! 460: #endif ! 461: static u_long unpst_sendspace = PIPSIZ; ! 462: static u_long unpst_recvspace = PIPSIZ; ! 463: static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ ! 464: static u_long unpdg_recvspace = 4*1024; ! 465: ! 466: static int unp_rights; /* file descriptors in flight */ ! 467: ! 468: SYSCTL_DECL(_net_local_stream); ! 469: SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, ! 470: &unpst_sendspace, 0, ""); ! 471: SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, ! 472: &unpst_recvspace, 0, ""); ! 473: SYSCTL_DECL(_net_local_dgram); ! 474: SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, ! 475: &unpdg_sendspace, 0, ""); ! 476: SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, ! 477: &unpdg_recvspace, 0, ""); ! 478: SYSCTL_DECL(_net_local); ! 479: SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, ""); ! 480: ! 481: static int ! 482: unp_attach(so) ! 483: struct socket *so; ! 484: { ! 485: register struct unpcb *unp; ! 486: int error; ! 487: ! 488: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { ! 489: switch (so->so_type) { ! 490: ! 491: case SOCK_STREAM: ! 492: error = soreserve(so, unpst_sendspace, unpst_recvspace); ! 493: break; ! 494: ! 495: case SOCK_DGRAM: ! 496: error = soreserve(so, unpdg_sendspace, unpdg_recvspace); ! 497: break; ! 498: ! 499: default: ! 500: panic("unp_attach"); ! 501: } ! 502: if (error) ! 503: return (error); ! 504: } ! 505: unp = zalloc(unp_zone); ! 506: if (unp == NULL) ! 507: return (ENOBUFS); ! 508: bzero(unp, sizeof *unp); ! 509: unp->unp_gencnt = ++unp_gencnt; ! 510: unp_count++; ! 511: LIST_INIT(&unp->unp_refs); ! 512: unp->unp_socket = so; ! 513: LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead ! 514: : &unp_shead, unp, unp_link); ! 515: so->so_pcb = (caddr_t)unp; ! 516: return (0); ! 517: } ! 518: ! 519: static void ! 520: unp_detach(unp) ! 521: register struct unpcb *unp; ! 522: { ! 523: LIST_REMOVE(unp, unp_link); ! 524: unp->unp_gencnt = ++unp_gencnt; ! 525: --unp_count; ! 526: if (unp->unp_vnode) { ! 527: unp->unp_vnode->v_socket = 0; ! 528: vrele(unp->unp_vnode); ! 529: unp->unp_vnode = 0; ! 530: } ! 531: if (unp->unp_conn) ! 532: unp_disconnect(unp); ! 533: while (unp->unp_refs.lh_first) ! 534: unp_drop(unp->unp_refs.lh_first, ECONNRESET); ! 535: soisdisconnected(unp->unp_socket); ! 536: unp->unp_socket->so_pcb = 0; ! 537: if (unp_rights) { ! 538: /* ! 539: * Normally the receive buffer is flushed later, ! 540: * in sofree, but if our receive buffer holds references ! 541: * to descriptors that are now garbage, we will dispose ! 542: * of those descriptor references after the garbage collector ! 543: * gets them (resulting in a "panic: closef: count < 0"). ! 544: */ ! 545: sorflush(unp->unp_socket); ! 546: unp_gc(); ! 547: } ! 548: if (unp->unp_addr) ! 549: FREE(unp->unp_addr, M_SONAME); ! 550: zfree(unp_zone, unp); ! 551: } ! 552: ! 553: static int ! 554: unp_bind(unp, nam, p) ! 555: struct unpcb *unp; ! 556: struct sockaddr *nam; ! 557: struct proc *p; ! 558: { ! 559: struct sockaddr_un *soun = (struct sockaddr_un *)nam; ! 560: register struct vnode *vp; ! 561: struct vattr vattr; ! 562: int error, namelen; ! 563: struct nameidata nd; ! 564: char buf[SOCK_MAXADDRLEN]; ! 565: ! 566: if (unp->unp_vnode != NULL) ! 567: return (EINVAL); ! 568: #define offsetof(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) ! 569: namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); ! 570: if (namelen <= 0) ! 571: return EINVAL; ! 572: strncpy(buf, soun->sun_path, namelen); ! 573: buf[namelen] = 0; /* null-terminate the string */ ! 574: NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, ! 575: buf, p); ! 576: /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ ! 577: error = namei(&nd); ! 578: if (error) ! 579: return (error); ! 580: vp = nd.ni_vp; ! 581: if (vp != NULL) { ! 582: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 583: if (nd.ni_dvp == vp) ! 584: vrele(nd.ni_dvp); ! 585: else ! 586: vput(nd.ni_dvp); ! 587: vrele(vp); ! 588: return (EADDRINUSE); ! 589: } ! 590: VATTR_NULL(&vattr); ! 591: vattr.va_type = VSOCK; ! 592: vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask); ! 593: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 594: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); ! 595: #if 0 ! 596: /* In FreeBSD create leave s parent held ; not here */ ! 597: vput(nd.ni_dvp); ! 598: #endif ! 599: if (error) ! 600: return (error); ! 601: vp = nd.ni_vp; ! 602: vp->v_socket = unp->unp_socket; ! 603: unp->unp_vnode = vp; ! 604: unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1); ! 605: VOP_UNLOCK(vp, 0, p); ! 606: return (0); ! 607: } ! 608: ! 609: static int ! 610: unp_connect(so, nam, p) ! 611: struct socket *so; ! 612: struct sockaddr *nam; ! 613: struct proc *p; ! 614: { ! 615: register struct sockaddr_un *soun = (struct sockaddr_un *)nam; ! 616: register struct vnode *vp; ! 617: register struct socket *so2, *so3; ! 618: struct unpcb *unp2, *unp3; ! 619: int error, len; ! 620: struct nameidata nd; ! 621: char buf[SOCK_MAXADDRLEN]; ! 622: ! 623: len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); ! 624: if (len <= 0) ! 625: return EINVAL; ! 626: strncpy(buf, soun->sun_path, len); ! 627: buf[len] = 0; ! 628: ! 629: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, p); ! 630: error = namei(&nd); ! 631: if (error) ! 632: return (error); ! 633: vp = nd.ni_vp; ! 634: if (vp->v_type != VSOCK) { ! 635: error = ENOTSOCK; ! 636: goto bad; ! 637: } ! 638: error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p); ! 639: if (error) ! 640: goto bad; ! 641: so2 = vp->v_socket; ! 642: if (so2 == 0) { ! 643: error = ECONNREFUSED; ! 644: goto bad; ! 645: } ! 646: if (so->so_type != so2->so_type) { ! 647: error = EPROTOTYPE; ! 648: goto bad; ! 649: } ! 650: if (so->so_proto->pr_flags & PR_CONNREQUIRED) { ! 651: if ((so2->so_options & SO_ACCEPTCONN) == 0 || ! 652: (so3 = sonewconn(so2, 0)) == 0) { ! 653: error = ECONNREFUSED; ! 654: goto bad; ! 655: } ! 656: unp2 = sotounpcb(so2); ! 657: unp3 = sotounpcb(so3); ! 658: if (unp2->unp_addr) ! 659: unp3->unp_addr = (struct sockaddr_un *) ! 660: dup_sockaddr((struct sockaddr *) ! 661: unp2->unp_addr, 1); ! 662: so2 = so3; ! 663: } ! 664: error = unp_connect2(so, so2); ! 665: bad: ! 666: vput(vp); ! 667: return (error); ! 668: } ! 669: ! 670: int ! 671: unp_connect2(so, so2) ! 672: register struct socket *so; ! 673: register struct socket *so2; ! 674: { ! 675: register struct unpcb *unp = sotounpcb(so); ! 676: register struct unpcb *unp2; ! 677: ! 678: if (so2->so_type != so->so_type) ! 679: return (EPROTOTYPE); ! 680: unp2 = sotounpcb(so2); ! 681: unp->unp_conn = unp2; ! 682: switch (so->so_type) { ! 683: ! 684: case SOCK_DGRAM: ! 685: LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); ! 686: soisconnected(so); ! 687: break; ! 688: ! 689: case SOCK_STREAM: ! 690: unp2->unp_conn = unp; ! 691: soisconnected(so); ! 692: soisconnected(so2); ! 693: break; ! 694: ! 695: default: ! 696: panic("unp_connect2"); ! 697: } ! 698: return (0); ! 699: } ! 700: ! 701: static void ! 702: unp_disconnect(unp) ! 703: struct unpcb *unp; ! 704: { ! 705: register struct unpcb *unp2 = unp->unp_conn; ! 706: ! 707: if (unp2 == 0) ! 708: return; ! 709: unp->unp_conn = 0; ! 710: switch (unp->unp_socket->so_type) { ! 711: ! 712: case SOCK_DGRAM: ! 713: LIST_REMOVE(unp, unp_reflink); ! 714: unp->unp_socket->so_state &= ~SS_ISCONNECTED; ! 715: break; ! 716: ! 717: case SOCK_STREAM: ! 718: soisdisconnected(unp->unp_socket); ! 719: unp2->unp_conn = 0; ! 720: soisdisconnected(unp2->unp_socket); ! 721: break; ! 722: } ! 723: } ! 724: ! 725: #ifdef notdef ! 726: void ! 727: unp_abort(unp) ! 728: struct unpcb *unp; ! 729: { ! 730: ! 731: unp_detach(unp); ! 732: } ! 733: #endif ! 734: ! 735: static int ! 736: unp_pcblist SYSCTL_HANDLER_ARGS ! 737: { ! 738: int error, i, n; ! 739: struct unpcb *unp, **unp_list; ! 740: unp_gen_t gencnt; ! 741: struct xunpgen xug; ! 742: struct unp_head *head; ! 743: ! 744: head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead); ! 745: ! 746: /* ! 747: * The process of preparing the PCB list is too time-consuming and ! 748: * resource-intensive to repeat twice on every request. ! 749: */ ! 750: if (req->oldptr == 0) { ! 751: n = unp_count; ! 752: req->oldidx = 2 * (sizeof xug) ! 753: + (n + n/8) * sizeof(struct xunpcb); ! 754: return 0; ! 755: } ! 756: ! 757: if (req->newptr != 0) ! 758: return EPERM; ! 759: ! 760: /* ! 761: * OK, now we're committed to doing something. ! 762: */ ! 763: gencnt = unp_gencnt; ! 764: n = unp_count; ! 765: ! 766: xug.xug_len = sizeof xug; ! 767: xug.xug_count = n; ! 768: xug.xug_gen = gencnt; ! 769: xug.xug_sogen = so_gencnt; ! 770: error = SYSCTL_OUT(req, &xug, sizeof xug); ! 771: if (error) ! 772: return error; ! 773: ! 774: unp_list = _MALLOC(n * sizeof *unp_list, M_TEMP, M_WAITOK); ! 775: if (unp_list == 0) ! 776: return ENOMEM; ! 777: ! 778: for (unp = head->lh_first, i = 0; unp && i < n; ! 779: unp = unp->unp_link.le_next) { ! 780: if (unp->unp_gencnt <= gencnt) ! 781: unp_list[i++] = unp; ! 782: } ! 783: n = i; /* in case we lost some during malloc */ ! 784: ! 785: error = 0; ! 786: for (i = 0; i < n; i++) { ! 787: unp = unp_list[i]; ! 788: if (unp->unp_gencnt <= gencnt) { ! 789: struct xunpcb xu; ! 790: xu.xu_len = sizeof xu; ! 791: xu.xu_unpp = unp; ! 792: /* ! 793: * XXX - need more locking here to protect against ! 794: * connect/disconnect races for SMP. ! 795: */ ! 796: if (unp->unp_addr) ! 797: bcopy(unp->unp_addr, &xu.xu_addr, ! 798: unp->unp_addr->sun_len); ! 799: if (unp->unp_conn && unp->unp_conn->unp_addr) ! 800: bcopy(unp->unp_conn->unp_addr, ! 801: &xu.xu_caddr, ! 802: unp->unp_conn->unp_addr->sun_len); ! 803: bcopy(unp, &xu.xu_unp, sizeof *unp); ! 804: sotoxsocket(unp->unp_socket, &xu.xu_socket); ! 805: error = SYSCTL_OUT(req, &xu, sizeof xu); ! 806: } ! 807: } ! 808: if (!error) { ! 809: /* ! 810: * Give the user an updated idea of our state. ! 811: * If the generation differs from what we told ! 812: * her before, she knows that something happened ! 813: * while we were processing this request, and it ! 814: * might be necessary to retry. ! 815: */ ! 816: xug.xug_gen = unp_gencnt; ! 817: xug.xug_sogen = so_gencnt; ! 818: xug.xug_count = unp_count; ! 819: error = SYSCTL_OUT(req, &xug, sizeof xug); ! 820: } ! 821: FREE(unp_list, M_TEMP); ! 822: return error; ! 823: } ! 824: ! 825: SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, ! 826: (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", ! 827: "List of active local datagram sockets"); ! 828: SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, ! 829: (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", ! 830: "List of active local stream sockets"); ! 831: ! 832: static void ! 833: unp_shutdown(unp) ! 834: struct unpcb *unp; ! 835: { ! 836: struct socket *so; ! 837: ! 838: if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && ! 839: (so = unp->unp_conn->unp_socket)) ! 840: socantrcvmore(so); ! 841: } ! 842: ! 843: static void ! 844: unp_drop(unp, errno) ! 845: struct unpcb *unp; ! 846: int errno; ! 847: { ! 848: struct socket *so = unp->unp_socket; ! 849: ! 850: so->so_error = errno; ! 851: unp_disconnect(unp); ! 852: if (so->so_head) { ! 853: LIST_REMOVE(unp, unp_link); ! 854: unp->unp_gencnt = ++unp_gencnt; ! 855: unp_count--; ! 856: so->so_pcb = (caddr_t) 0; ! 857: if (unp->unp_addr) ! 858: FREE(unp->unp_addr, M_SONAME); ! 859: zfree(unp_zone, unp); ! 860: sofree(so); ! 861: } ! 862: } ! 863: ! 864: #ifdef notdef ! 865: void ! 866: unp_drain() ! 867: { ! 868: ! 869: } ! 870: #endif ! 871: ! 872: int ! 873: unp_externalize(rights) ! 874: struct mbuf *rights; ! 875: { ! 876: struct proc *p = current_proc(); /* XXX */ ! 877: register int i; ! 878: register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); ! 879: register struct file **rp = (struct file **)(cm + 1); ! 880: register struct file *fp; ! 881: int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); ! 882: int f; ! 883: ! 884: /* ! 885: * if the new FD's will not fit, then we free them all ! 886: */ ! 887: if (!fdavail(p, newfds)) { ! 888: for (i = 0; i < newfds; i++) { ! 889: fp = *rp; ! 890: unp_discard(fp); ! 891: *rp++ = 0; ! 892: } ! 893: return (EMSGSIZE); ! 894: } ! 895: /* ! 896: * now change each pointer to an fd in the global table to ! 897: * an integer that is the index to the local fd table entry ! 898: * that we set up to point to the global one we are transferring. ! 899: * XXX this assumes a pointer and int are the same size...! ! 900: */ ! 901: for (i = 0; i < newfds; i++) { ! 902: if (fdalloc(p, 0, &f)) ! 903: panic("unp_externalize"); ! 904: fp = *rp; ! 905: p->p_fd->fd_ofiles[f] = fp; ! 906: fp->f_msgcount--; ! 907: unp_rights--; ! 908: *(int *)rp++ = f; ! 909: } ! 910: return (0); ! 911: } ! 912: ! 913: void ! 914: unp_init(void) ! 915: { ! 916: unp_zone = zinit(sizeof(struct unpcb), ! 917: (nmbclusters * sizeof(struct unpcb)), ! 918: 4096, "unpzone"); ! 919: if (unp_zone == 0) ! 920: panic("unp_init"); ! 921: LIST_INIT(&unp_dhead); ! 922: LIST_INIT(&unp_shead); ! 923: } ! 924: ! 925: #ifndef MIN ! 926: #define MIN(a,b) (((a)<(b))?(a):(b)) ! 927: #endif ! 928: ! 929: static int ! 930: unp_internalize(control, p) ! 931: struct mbuf *control; ! 932: struct proc *p; ! 933: { ! 934: register struct cmsghdr *cm = mtod(control, struct cmsghdr *); ! 935: register struct file **rp; ! 936: struct file *fp; ! 937: register int i, error; ! 938: int oldfds; ! 939: ! 940: if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || ! 941: cm->cmsg_len != control->m_len) ! 942: return (EINVAL); ! 943: oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); ! 944: rp = (struct file **)(cm + 1); ! 945: for (i = 0; i < oldfds; i++) ! 946: if (error = fdgetf(p, *(int *)rp++, 0)) ! 947: return (error); ! 948: rp = (struct file **)(cm + 1); ! 949: for (i = 0; i < oldfds; i++) { ! 950: (void) fdgetf(p, *(int *)rp, &fp); ! 951: *rp++ = fp; ! 952: fp->f_count++; ! 953: if (fp->f_count <= 0) ! 954: panic("unp_internalize f_count"); ! 955: fp->f_msgcount++; ! 956: unp_rights++; ! 957: } ! 958: return (0); ! 959: } ! 960: ! 961: static int unp_defer, unp_gcing; ! 962: ! 963: static void ! 964: unp_gc() ! 965: { ! 966: register struct file *fp, *nextfp; ! 967: register struct socket *so; ! 968: struct file **extra_ref, **fpp; ! 969: int nunref, i; ! 970: ! 971: if (unp_gcing) ! 972: return; ! 973: unp_gcing = 1; ! 974: unp_defer = 0; ! 975: /* ! 976: * before going through all this, set all FDs to ! 977: * be NOT defered and NOT externally accessible ! 978: */ ! 979: for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) ! 980: fp->f_flag &= ~(FMARK|FDEFER); ! 981: do { ! 982: for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { ! 983: /* ! 984: * If the file is not open, skip it ! 985: */ ! 986: if (fp->f_count == 0) ! 987: continue; ! 988: /* ! 989: * If we already marked it as 'defer' in a ! 990: * previous pass, then try process it this time ! 991: * and un-mark it ! 992: */ ! 993: if (fp->f_flag & FDEFER) { ! 994: fp->f_flag &= ~FDEFER; ! 995: unp_defer--; ! 996: } else { ! 997: /* ! 998: * if it's not defered, then check if it's ! 999: * already marked.. if so skip it ! 1000: */ ! 1001: if (fp->f_flag & FMARK) ! 1002: continue; ! 1003: /* ! 1004: * If all references are from messages ! 1005: * in transit, then skip it. it's not ! 1006: * externally accessible. ! 1007: */ ! 1008: if (fp->f_count == fp->f_msgcount) ! 1009: continue; ! 1010: /* ! 1011: * If it got this far then it must be ! 1012: * externally accessible. ! 1013: */ ! 1014: fp->f_flag |= FMARK; ! 1015: } ! 1016: /* ! 1017: * either it was defered, or it is externally ! 1018: * accessible and not already marked so. ! 1019: * Now check if it is possibly one of OUR sockets. ! 1020: */ ! 1021: if (fp->f_type != DTYPE_SOCKET || ! 1022: (so = (struct socket *)fp->f_data) == 0) ! 1023: continue; ! 1024: if (so->so_proto->pr_domain != &localdomain || ! 1025: (so->so_proto->pr_flags&PR_RIGHTS) == 0) ! 1026: continue; ! 1027: #ifdef notdef ! 1028: if (so->so_rcv.sb_flags & SB_LOCK) { ! 1029: /* ! 1030: * This is problematical; it's not clear ! 1031: * we need to wait for the sockbuf to be ! 1032: * unlocked (on a uniprocessor, at least), ! 1033: * and it's also not clear what to do ! 1034: * if sbwait returns an error due to receipt ! 1035: * of a signal. If sbwait does return ! 1036: * an error, we'll go into an infinite ! 1037: * loop. Delete all of this for now. ! 1038: */ ! 1039: (void) sbwait(&so->so_rcv); ! 1040: goto restart; ! 1041: } ! 1042: #endif ! 1043: /* ! 1044: * So, Ok, it's one of our sockets and it IS externally ! 1045: * accessible (or was defered). Now we look ! 1046: * to see if we hold any file descriptors in its ! 1047: * message buffers. Follow those links and mark them ! 1048: * as accessible too. ! 1049: */ ! 1050: unp_scan(so->so_rcv.sb_mb, unp_mark); ! 1051: } ! 1052: } while (unp_defer); ! 1053: /* ! 1054: * We grab an extra reference to each of the file table entries ! 1055: * that are not otherwise accessible and then free the rights ! 1056: * that are stored in messages on them. ! 1057: * ! 1058: * The bug in the orginal code is a little tricky, so I'll describe ! 1059: * what's wrong with it here. ! 1060: * ! 1061: * It is incorrect to simply unp_discard each entry for f_msgcount ! 1062: * times -- consider the case of sockets A and B that contain ! 1063: * references to each other. On a last close of some other socket, ! 1064: * we trigger a gc since the number of outstanding rights (unp_rights) ! 1065: * is non-zero. If during the sweep phase the gc code un_discards, ! 1066: * we end up doing a (full) closef on the descriptor. A closef on A ! 1067: * results in the following chain. Closef calls soo_close, which ! 1068: * calls soclose. Soclose calls first (through the switch ! 1069: * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply ! 1070: * returns because the previous instance had set unp_gcing, and ! 1071: * we return all the way back to soclose, which marks the socket ! 1072: * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush ! 1073: * to free up the rights that are queued in messages on the socket A, ! 1074: * i.e., the reference on B. The sorflush calls via the dom_dispose ! 1075: * switch unp_dispose, which unp_scans with unp_discard. This second ! 1076: * instance of unp_discard just calls closef on B. ! 1077: * ! 1078: * Well, a similar chain occurs on B, resulting in a sorflush on B, ! 1079: * which results in another closef on A. Unfortunately, A is already ! 1080: * being closed, and the descriptor has already been marked with ! 1081: * SS_NOFDREF, and soclose panics at this point. ! 1082: * ! 1083: * Here, we first take an extra reference to each inaccessible ! 1084: * descriptor. Then, we call sorflush ourself, since we know ! 1085: * it is a Unix domain socket anyhow. After we destroy all the ! 1086: * rights carried in messages, we do a last closef to get rid ! 1087: * of our extra reference. This is the last close, and the ! 1088: * unp_detach etc will shut down the socket. ! 1089: * ! 1090: * 91/09/19, [email protected] ! 1091: */ ! 1092: extra_ref = _MALLOC(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); ! 1093: for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0; ! 1094: fp = nextfp) { ! 1095: nextfp = fp->f_list.le_next; ! 1096: /* ! 1097: * If it's not open, skip it ! 1098: */ ! 1099: if (fp->f_count == 0) ! 1100: continue; ! 1101: /* ! 1102: * If all refs are from msgs, and it's not marked accessible ! 1103: * then it must be referenced from some unreachable cycle ! 1104: * of (shut-down) FDs, so include it in our ! 1105: * list of FDs to remove ! 1106: */ ! 1107: if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { ! 1108: *fpp++ = fp; ! 1109: nunref++; ! 1110: fp->f_count++; ! 1111: if (fp->f_count <= 0) ! 1112: panic("unp_gc f_count"); ! 1113: } ! 1114: } ! 1115: /* ! 1116: * for each FD on our hit list, do the following two things ! 1117: */ ! 1118: for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) { ! 1119: struct file *tfp = *fpp; ! 1120: if (tfp->f_type == DTYPE_SOCKET && tfp->f_data != NULL) ! 1121: sorflush((struct socket *)(tfp->f_data)); ! 1122: } ! 1123: ! 1124: ! 1125: for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) ! 1126: closef(*fpp, (struct proc *) NULL); ! 1127: FREE((caddr_t)extra_ref, M_FILE); ! 1128: unp_gcing = 0; ! 1129: } ! 1130: ! 1131: void ! 1132: unp_dispose(m) ! 1133: struct mbuf *m; ! 1134: { ! 1135: ! 1136: if (m) ! 1137: unp_scan(m, unp_discard); ! 1138: } ! 1139: ! 1140: static void ! 1141: unp_scan(m0, op) ! 1142: register struct mbuf *m0; ! 1143: void (*op) __P((struct file *)); ! 1144: { ! 1145: register struct mbuf *m; ! 1146: register struct file **rp; ! 1147: register struct cmsghdr *cm; ! 1148: register int i; ! 1149: int qfds; ! 1150: ! 1151: while (m0) { ! 1152: for (m = m0; m; m = m->m_next) ! 1153: if (m->m_type == MT_CONTROL && ! 1154: m->m_len >= sizeof(*cm)) { ! 1155: cm = mtod(m, struct cmsghdr *); ! 1156: if (cm->cmsg_level != SOL_SOCKET || ! 1157: cm->cmsg_type != SCM_RIGHTS) ! 1158: continue; ! 1159: qfds = (cm->cmsg_len - sizeof *cm) ! 1160: / sizeof (struct file *); ! 1161: rp = (struct file **)(cm + 1); ! 1162: for (i = 0; i < qfds; i++) ! 1163: (*op)(*rp++); ! 1164: break; /* XXX, but saves time */ ! 1165: } ! 1166: m0 = m0->m_act; ! 1167: } ! 1168: } ! 1169: ! 1170: static void ! 1171: unp_mark(fp) ! 1172: struct file *fp; ! 1173: { ! 1174: ! 1175: if (fp->f_flag & FMARK) ! 1176: return; ! 1177: unp_defer++; ! 1178: fp->f_flag |= (FMARK|FDEFER); ! 1179: } ! 1180: ! 1181: static void ! 1182: unp_discard(fp) ! 1183: struct file *fp; ! 1184: { ! 1185: ! 1186: fp->f_msgcount--; ! 1187: unp_rights--; ! 1188: (void) closef(fp, (struct proc *)NULL); ! 1189: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.