Annotation of sys/kern/uipc_syscalls.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uipc_syscalls.c,v 1.66 2006/10/23 07:13:56 henning Exp $ */
! 2: /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989, 1990, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/filedesc.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/file.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/malloc.h>
! 42: #include <sys/event.h>
! 43: #include <sys/mbuf.h>
! 44: #include <sys/protosw.h>
! 45: #include <sys/socket.h>
! 46: #include <sys/socketvar.h>
! 47: #include <sys/signalvar.h>
! 48: #include <sys/unpcb.h>
! 49: #include <sys/un.h>
! 50: #ifdef KTRACE
! 51: #include <sys/ktrace.h>
! 52: #endif
! 53:
! 54: #include <sys/mount.h>
! 55: #include <sys/syscallargs.h>
! 56:
! 57: /*
! 58: * System call interface to the socket abstraction.
! 59: */
! 60: extern struct fileops socketops;
! 61:
! 62: int
! 63: sys_socket(struct proc *p, void *v, register_t *retval)
! 64: {
! 65: struct sys_socket_args /* {
! 66: syscallarg(int) domain;
! 67: syscallarg(int) type;
! 68: syscallarg(int) protocol;
! 69: } */ *uap = v;
! 70: struct filedesc *fdp = p->p_fd;
! 71: struct socket *so;
! 72: struct file *fp;
! 73: int fd, error;
! 74:
! 75: fdplock(fdp);
! 76:
! 77: if ((error = falloc(p, &fp, &fd)) != 0)
! 78: goto out;
! 79: fp->f_flag = FREAD|FWRITE;
! 80: fp->f_type = DTYPE_SOCKET;
! 81: fp->f_ops = &socketops;
! 82: error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
! 83: SCARG(uap, protocol));
! 84: if (error) {
! 85: fdremove(fdp, fd);
! 86: closef(fp, p);
! 87: } else {
! 88: fp->f_data = so;
! 89: FILE_SET_MATURE(fp);
! 90: *retval = fd;
! 91: }
! 92: out:
! 93: fdpunlock(fdp);
! 94: return (error);
! 95: }
! 96:
! 97: /* ARGSUSED */
! 98: int
! 99: sys_bind(struct proc *p, void *v, register_t *retval)
! 100: {
! 101: struct sys_bind_args /* {
! 102: syscallarg(int) s;
! 103: syscallarg(const struct sockaddr *) name;
! 104: syscallarg(socklen_t) namelen;
! 105: } */ *uap = v;
! 106: struct file *fp;
! 107: struct mbuf *nam;
! 108: int error;
! 109:
! 110: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 111: return (error);
! 112: error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
! 113: MT_SONAME);
! 114: if (error == 0) {
! 115: error = sobind(fp->f_data, nam);
! 116: m_freem(nam);
! 117: }
! 118: FRELE(fp);
! 119: return (error);
! 120: }
! 121:
! 122: /* ARGSUSED */
! 123: int
! 124: sys_listen(struct proc *p, void *v, register_t *retval)
! 125: {
! 126: struct sys_listen_args /* {
! 127: syscallarg(int) s;
! 128: syscallarg(int) backlog;
! 129: } */ *uap = v;
! 130: struct file *fp;
! 131: int error;
! 132:
! 133: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 134: return (error);
! 135: error = solisten(fp->f_data, SCARG(uap, backlog));
! 136: FRELE(fp);
! 137: return (error);
! 138: }
! 139:
! 140: int
! 141: sys_accept(struct proc *p, void *v, register_t *retval)
! 142: {
! 143: struct sys_accept_args /* {
! 144: syscallarg(int) s;
! 145: syscallarg(struct sockaddr *) name;
! 146: syscallarg(socklen_t *) anamelen;
! 147: } */ *uap = v;
! 148: struct file *fp, *headfp;
! 149: struct mbuf *nam;
! 150: socklen_t namelen;
! 151: int error, s, tmpfd;
! 152: struct socket *head, *so;
! 153: int nflag;
! 154:
! 155: if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen),
! 156: &namelen, sizeof (namelen))))
! 157: return (error);
! 158: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 159: return (error);
! 160: headfp = fp;
! 161: s = splsoftnet();
! 162: head = fp->f_data;
! 163: if ((head->so_options & SO_ACCEPTCONN) == 0) {
! 164: error = EINVAL;
! 165: goto bad;
! 166: }
! 167: if ((head->so_state & SS_NBIO) && head->so_qlen == 0) {
! 168: if (head->so_state & SS_CANTRCVMORE)
! 169: error = ECONNABORTED;
! 170: else
! 171: error = EWOULDBLOCK;
! 172: goto bad;
! 173: }
! 174: while (head->so_qlen == 0 && head->so_error == 0) {
! 175: if (head->so_state & SS_CANTRCVMORE) {
! 176: head->so_error = ECONNABORTED;
! 177: break;
! 178: }
! 179: error = tsleep(&head->so_timeo, PSOCK | PCATCH, netcon, 0);
! 180: if (error) {
! 181: goto bad;
! 182: }
! 183: }
! 184: if (head->so_error) {
! 185: error = head->so_error;
! 186: head->so_error = 0;
! 187: goto bad;
! 188: }
! 189:
! 190: /*
! 191: * At this point we know that there is at least one connection
! 192: * ready to be accepted. Remove it from the queue prior to
! 193: * allocating the file descriptor for it since falloc() may
! 194: * block allowing another process to accept the connection
! 195: * instead.
! 196: */
! 197: so = TAILQ_FIRST(&head->so_q);
! 198: if (soqremque(so, 1) == 0)
! 199: panic("accept");
! 200:
! 201: /* Take note if socket was non-blocking. */
! 202: nflag = (fp->f_flag & FNONBLOCK);
! 203:
! 204: fdplock(p->p_fd);
! 205: if ((error = falloc(p, &fp, &tmpfd)) != 0) {
! 206: /*
! 207: * Probably ran out of file descriptors. Put the
! 208: * unaccepted connection back onto the queue and
! 209: * do another wakeup so some other process might
! 210: * have a chance at it.
! 211: */
! 212: so->so_head = head;
! 213: head->so_qlen++;
! 214: so->so_onq = &head->so_q;
! 215: TAILQ_INSERT_HEAD(so->so_onq, so, so_qe);
! 216: wakeup_one(&head->so_timeo);
! 217: goto bad;
! 218: }
! 219: *retval = tmpfd;
! 220:
! 221: /* connection has been removed from the listen queue */
! 222: KNOTE(&head->so_rcv.sb_sel.si_note, 0);
! 223:
! 224: fp->f_type = DTYPE_SOCKET;
! 225: fp->f_flag = FREAD | FWRITE | nflag;
! 226: fp->f_ops = &socketops;
! 227: fp->f_data = so;
! 228: nam = m_get(M_WAIT, MT_SONAME);
! 229: error = soaccept(so, nam);
! 230: if (!error && SCARG(uap, name)) {
! 231: if (namelen > nam->m_len)
! 232: namelen = nam->m_len;
! 233: /* SHOULD COPY OUT A CHAIN HERE */
! 234: if ((error = copyout(mtod(nam, caddr_t),
! 235: SCARG(uap, name), namelen)) == 0)
! 236: error = copyout(&namelen, SCARG(uap, anamelen),
! 237: sizeof (*SCARG(uap, anamelen)));
! 238: }
! 239: /* if an error occurred, free the file descriptor */
! 240: if (error) {
! 241: fdremove(p->p_fd, tmpfd);
! 242: closef(fp, p);
! 243: } else {
! 244: FILE_SET_MATURE(fp);
! 245: }
! 246: m_freem(nam);
! 247: bad:
! 248: fdpunlock(p->p_fd);
! 249: splx(s);
! 250: FRELE(headfp);
! 251: return (error);
! 252: }
! 253:
! 254: /* ARGSUSED */
! 255: int
! 256: sys_connect(struct proc *p, void *v, register_t *retval)
! 257: {
! 258: struct sys_connect_args /* {
! 259: syscallarg(int) s;
! 260: syscallarg(const struct sockaddr *) name;
! 261: syscallarg(socklen_t) namelen;
! 262: } */ *uap = v;
! 263: struct file *fp;
! 264: struct socket *so;
! 265: struct mbuf *nam = NULL;
! 266: int error, s;
! 267:
! 268: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 269: return (error);
! 270: so = fp->f_data;
! 271: if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
! 272: FRELE(fp);
! 273: return (EALREADY);
! 274: }
! 275: error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
! 276: MT_SONAME);
! 277: if (error)
! 278: goto bad;
! 279: error = soconnect(so, nam);
! 280: if (error)
! 281: goto bad;
! 282: if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
! 283: FRELE(fp);
! 284: m_freem(nam);
! 285: return (EINPROGRESS);
! 286: }
! 287: s = splsoftnet();
! 288: while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
! 289: error = tsleep(&so->so_timeo, PSOCK | PCATCH,
! 290: netcon, 0);
! 291: if (error)
! 292: break;
! 293: }
! 294: if (error == 0) {
! 295: error = so->so_error;
! 296: so->so_error = 0;
! 297: }
! 298: splx(s);
! 299: bad:
! 300: so->so_state &= ~SS_ISCONNECTING;
! 301: FRELE(fp);
! 302: if (nam)
! 303: m_freem(nam);
! 304: if (error == ERESTART)
! 305: error = EINTR;
! 306: return (error);
! 307: }
! 308:
! 309: int
! 310: sys_socketpair(struct proc *p, void *v, register_t *retval)
! 311: {
! 312: struct sys_socketpair_args /* {
! 313: syscallarg(int) domain;
! 314: syscallarg(int) type;
! 315: syscallarg(int) protocol;
! 316: syscallarg(int *) rsv;
! 317: } */ *uap = v;
! 318: struct filedesc *fdp = p->p_fd;
! 319: struct file *fp1, *fp2;
! 320: struct socket *so1, *so2;
! 321: int fd, error, sv[2];
! 322:
! 323: error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
! 324: SCARG(uap, protocol));
! 325: if (error)
! 326: return (error);
! 327: error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
! 328: SCARG(uap, protocol));
! 329: if (error)
! 330: goto free1;
! 331:
! 332: fdplock(fdp);
! 333: if ((error = falloc(p, &fp1, &fd)) != 0)
! 334: goto free2;
! 335: sv[0] = fd;
! 336: fp1->f_flag = FREAD|FWRITE;
! 337: fp1->f_type = DTYPE_SOCKET;
! 338: fp1->f_ops = &socketops;
! 339: fp1->f_data = so1;
! 340: if ((error = falloc(p, &fp2, &fd)) != 0)
! 341: goto free3;
! 342: fp2->f_flag = FREAD|FWRITE;
! 343: fp2->f_type = DTYPE_SOCKET;
! 344: fp2->f_ops = &socketops;
! 345: fp2->f_data = so2;
! 346: sv[1] = fd;
! 347: if ((error = soconnect2(so1, so2)) != 0)
! 348: goto free4;
! 349: if (SCARG(uap, type) == SOCK_DGRAM) {
! 350: /*
! 351: * Datagram socket connection is asymmetric.
! 352: */
! 353: if ((error = soconnect2(so2, so1)) != 0)
! 354: goto free4;
! 355: }
! 356: error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
! 357: if (error == 0) {
! 358: FILE_SET_MATURE(fp1);
! 359: FILE_SET_MATURE(fp2);
! 360: fdpunlock(fdp);
! 361: return (0);
! 362: }
! 363: free4:
! 364: fdremove(fdp, sv[1]);
! 365: closef(fp2, p);
! 366: so2 = NULL;
! 367: free3:
! 368: fdremove(fdp, sv[0]);
! 369: closef(fp1, p);
! 370: so1 = NULL;
! 371: free2:
! 372: if (so2 != NULL)
! 373: (void)soclose(so2);
! 374: fdpunlock(fdp);
! 375: free1:
! 376: if (so1 != NULL)
! 377: (void)soclose(so1);
! 378: return (error);
! 379: }
! 380:
! 381: int
! 382: sys_sendto(struct proc *p, void *v, register_t *retval)
! 383: {
! 384: struct sys_sendto_args /* {
! 385: syscallarg(int) s;
! 386: syscallarg(const void *) buf;
! 387: syscallarg(size_t) len;
! 388: syscallarg(int) flags;
! 389: syscallarg(const struct sockaddr *) to;
! 390: syscallarg(socklen_t) tolen;
! 391: } */ *uap = v;
! 392: struct msghdr msg;
! 393: struct iovec aiov;
! 394:
! 395: msg.msg_name = (caddr_t)SCARG(uap, to);
! 396: msg.msg_namelen = SCARG(uap, tolen);
! 397: msg.msg_iov = &aiov;
! 398: msg.msg_iovlen = 1;
! 399: msg.msg_control = 0;
! 400: #ifdef COMPAT_OLDSOCK
! 401: msg.msg_flags = 0;
! 402: #endif
! 403: aiov.iov_base = (char *)SCARG(uap, buf);
! 404: aiov.iov_len = SCARG(uap, len);
! 405: return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
! 406: }
! 407:
! 408: int
! 409: sys_sendmsg(struct proc *p, void *v, register_t *retval)
! 410: {
! 411: struct sys_sendmsg_args /* {
! 412: syscallarg(int) s;
! 413: syscallarg(const struct msghdr *) msg;
! 414: syscallarg(int) flags;
! 415: } */ *uap = v;
! 416: struct msghdr msg;
! 417: struct iovec aiov[UIO_SMALLIOV], *iov;
! 418: int error;
! 419:
! 420: error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
! 421: if (error)
! 422: return (error);
! 423: if (msg.msg_iovlen > IOV_MAX)
! 424: return (EMSGSIZE);
! 425: if (msg.msg_iovlen > UIO_SMALLIOV)
! 426: iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
! 427: M_IOV, M_WAITOK);
! 428: else
! 429: iov = aiov;
! 430: if (msg.msg_iovlen &&
! 431: (error = copyin(msg.msg_iov, iov,
! 432: (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
! 433: goto done;
! 434: msg.msg_iov = iov;
! 435: #ifdef COMPAT_OLDSOCK
! 436: msg.msg_flags = 0;
! 437: #endif
! 438: error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
! 439: done:
! 440: if (iov != aiov)
! 441: free(iov, M_IOV);
! 442: return (error);
! 443: }
! 444:
! 445: int
! 446: sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
! 447: {
! 448: struct file *fp;
! 449: struct uio auio;
! 450: struct iovec *iov;
! 451: int i;
! 452: struct mbuf *to, *control;
! 453: int len, error;
! 454: #ifdef KTRACE
! 455: struct iovec *ktriov = NULL;
! 456: #endif
! 457:
! 458: to = NULL;
! 459:
! 460: if ((error = getsock(p->p_fd, s, &fp)) != 0)
! 461: return (error);
! 462: auio.uio_iov = mp->msg_iov;
! 463: auio.uio_iovcnt = mp->msg_iovlen;
! 464: auio.uio_segflg = UIO_USERSPACE;
! 465: auio.uio_rw = UIO_WRITE;
! 466: auio.uio_procp = p;
! 467: auio.uio_offset = 0; /* XXX */
! 468: auio.uio_resid = 0;
! 469: iov = mp->msg_iov;
! 470: for (i = 0; i < mp->msg_iovlen; i++, iov++) {
! 471: /* Don't allow sum > SSIZE_MAX */
! 472: if (iov->iov_len > SSIZE_MAX ||
! 473: (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
! 474: error = EINVAL;
! 475: goto bad;
! 476: }
! 477: }
! 478: if (mp->msg_name) {
! 479: error = sockargs(&to, mp->msg_name, mp->msg_namelen,
! 480: MT_SONAME);
! 481: if (error)
! 482: goto bad;
! 483: }
! 484: if (mp->msg_control) {
! 485: if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))
! 486: #ifdef COMPAT_OLDSOCK
! 487: && mp->msg_flags != MSG_COMPAT
! 488: #endif
! 489: ) {
! 490: error = EINVAL;
! 491: goto bad;
! 492: }
! 493: error = sockargs(&control, mp->msg_control,
! 494: mp->msg_controllen, MT_CONTROL);
! 495: if (error)
! 496: goto bad;
! 497: #ifdef COMPAT_OLDSOCK
! 498: if (mp->msg_flags == MSG_COMPAT) {
! 499: struct cmsghdr *cm;
! 500:
! 501: M_PREPEND(control, sizeof(*cm), M_WAIT);
! 502: cm = mtod(control, struct cmsghdr *);
! 503: cm->cmsg_len = control->m_len;
! 504: cm->cmsg_level = SOL_SOCKET;
! 505: cm->cmsg_type = SCM_RIGHTS;
! 506: }
! 507: #endif
! 508: } else
! 509: control = 0;
! 510: #ifdef KTRACE
! 511: if (KTRPOINT(p, KTR_GENIO)) {
! 512: int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
! 513:
! 514: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
! 515: bcopy(auio.uio_iov, ktriov, iovlen);
! 516: }
! 517: #endif
! 518: len = auio.uio_resid;
! 519: error = sosend(fp->f_data, to, &auio, NULL, control, flags);
! 520: if (error) {
! 521: if (auio.uio_resid != len && (error == ERESTART ||
! 522: error == EINTR || error == EWOULDBLOCK))
! 523: error = 0;
! 524: if (error == EPIPE)
! 525: psignal(p, SIGPIPE);
! 526: }
! 527: if (error == 0) {
! 528: *retsize = len - auio.uio_resid;
! 529: fp->f_wxfer++;
! 530: fp->f_wbytes += *retsize;
! 531: }
! 532: #ifdef KTRACE
! 533: if (ktriov != NULL) {
! 534: if (error == 0)
! 535: ktrgenio(p, s, UIO_WRITE, ktriov, *retsize, error);
! 536: free(ktriov, M_TEMP);
! 537: }
! 538: #endif
! 539: bad:
! 540: FRELE(fp);
! 541: if (to)
! 542: m_freem(to);
! 543: return (error);
! 544: }
! 545:
! 546: int
! 547: sys_recvfrom(struct proc *p, void *v, register_t *retval)
! 548: {
! 549: struct sys_recvfrom_args /* {
! 550: syscallarg(int) s;
! 551: syscallarg(void *) buf;
! 552: syscallarg(size_t) len;
! 553: syscallarg(int) flags;
! 554: syscallarg(struct sockaddr *) from;
! 555: syscallarg(socklen_t *) fromlenaddr;
! 556: } */ *uap = v;
! 557: struct msghdr msg;
! 558: struct iovec aiov;
! 559: int error;
! 560:
! 561: if (SCARG(uap, fromlenaddr)) {
! 562: error = copyin(SCARG(uap, fromlenaddr),
! 563: &msg.msg_namelen, sizeof (msg.msg_namelen));
! 564: if (error)
! 565: return (error);
! 566: } else
! 567: msg.msg_namelen = 0;
! 568: msg.msg_name = (caddr_t)SCARG(uap, from);
! 569: msg.msg_iov = &aiov;
! 570: msg.msg_iovlen = 1;
! 571: aiov.iov_base = SCARG(uap, buf);
! 572: aiov.iov_len = SCARG(uap, len);
! 573: msg.msg_control = 0;
! 574: msg.msg_flags = SCARG(uap, flags);
! 575: return (recvit(p, SCARG(uap, s), &msg,
! 576: (caddr_t)SCARG(uap, fromlenaddr), retval));
! 577: }
! 578:
! 579: int
! 580: sys_recvmsg(struct proc *p, void *v, register_t *retval)
! 581: {
! 582: struct sys_recvmsg_args /* {
! 583: syscallarg(int) s;
! 584: syscallarg(struct msghdr *) msg;
! 585: syscallarg(int) flags;
! 586: } */ *uap = v;
! 587: struct msghdr msg;
! 588: struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
! 589: int error;
! 590:
! 591: error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
! 592: if (error)
! 593: return (error);
! 594: if (msg.msg_iovlen > IOV_MAX)
! 595: return (EMSGSIZE);
! 596: if (msg.msg_iovlen > UIO_SMALLIOV)
! 597: iov = malloc(sizeof(struct iovec) * msg.msg_iovlen,
! 598: M_IOV, M_WAITOK);
! 599: else
! 600: iov = aiov;
! 601: #ifdef COMPAT_OLDSOCK
! 602: msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
! 603: #else
! 604: msg.msg_flags = SCARG(uap, flags);
! 605: #endif
! 606: if (msg.msg_iovlen > 0) {
! 607: error = copyin(msg.msg_iov, iov,
! 608: (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
! 609: if (error)
! 610: goto done;
! 611: }
! 612: uiov = msg.msg_iov;
! 613: msg.msg_iov = iov;
! 614: if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
! 615: msg.msg_iov = uiov;
! 616: error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
! 617: }
! 618: done:
! 619: if (iov != aiov)
! 620: free(iov, M_IOV);
! 621: return (error);
! 622: }
! 623:
! 624: int
! 625: recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
! 626: register_t *retsize)
! 627: {
! 628: struct file *fp;
! 629: struct uio auio;
! 630: struct iovec *iov;
! 631: int i;
! 632: size_t len;
! 633: int error;
! 634: struct mbuf *from = NULL, *control = NULL;
! 635: #ifdef KTRACE
! 636: struct iovec *ktriov = NULL;
! 637: #endif
! 638:
! 639: if ((error = getsock(p->p_fd, s, &fp)) != 0)
! 640: return (error);
! 641: auio.uio_iov = mp->msg_iov;
! 642: auio.uio_iovcnt = mp->msg_iovlen;
! 643: auio.uio_segflg = UIO_USERSPACE;
! 644: auio.uio_rw = UIO_READ;
! 645: auio.uio_procp = p;
! 646: auio.uio_offset = 0; /* XXX */
! 647: auio.uio_resid = 0;
! 648: iov = mp->msg_iov;
! 649: for (i = 0; i < mp->msg_iovlen; i++, iov++) {
! 650: /* Don't allow sum > SSIZE_MAX */
! 651: if (iov->iov_len > SSIZE_MAX ||
! 652: (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
! 653: error = EINVAL;
! 654: goto out;
! 655: }
! 656: }
! 657: #ifdef KTRACE
! 658: if (KTRPOINT(p, KTR_GENIO)) {
! 659: int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
! 660:
! 661: ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
! 662: bcopy(auio.uio_iov, ktriov, iovlen);
! 663: }
! 664: #endif
! 665: len = auio.uio_resid;
! 666: error = soreceive(fp->f_data, &from, &auio, NULL,
! 667: mp->msg_control ? &control : NULL,
! 668: &mp->msg_flags);
! 669: if (error) {
! 670: if (auio.uio_resid != len && (error == ERESTART ||
! 671: error == EINTR || error == EWOULDBLOCK))
! 672: error = 0;
! 673: }
! 674: #ifdef KTRACE
! 675: if (ktriov != NULL) {
! 676: if (error == 0)
! 677: ktrgenio(p, s, UIO_READ,
! 678: ktriov, len - auio.uio_resid, error);
! 679: free(ktriov, M_TEMP);
! 680: }
! 681: #endif
! 682: if (error)
! 683: goto out;
! 684: *retsize = len - auio.uio_resid;
! 685: if (mp->msg_name) {
! 686: socklen_t alen;
! 687:
! 688: if (from == NULL)
! 689: alen = 0;
! 690: else {
! 691: /* save sa_len before it is destroyed by MSG_COMPAT */
! 692: alen = mp->msg_namelen;
! 693: if (alen > from->m_len)
! 694: alen = from->m_len;
! 695: /* else if alen < from->m_len ??? */
! 696: #ifdef COMPAT_OLDSOCK
! 697: if (mp->msg_flags & MSG_COMPAT)
! 698: mtod(from, struct osockaddr *)->sa_family =
! 699: mtod(from, struct sockaddr *)->sa_family;
! 700: #endif
! 701: error = copyout(mtod(from, caddr_t), mp->msg_name, alen);
! 702: if (error)
! 703: goto out;
! 704: }
! 705: mp->msg_namelen = alen;
! 706: if (namelenp &&
! 707: (error = copyout(&alen, namelenp, sizeof(alen)))) {
! 708: #ifdef COMPAT_OLDSOCK
! 709: if (mp->msg_flags & MSG_COMPAT)
! 710: error = 0; /* old recvfrom didn't check */
! 711: else
! 712: #endif
! 713: goto out;
! 714: }
! 715: }
! 716: if (mp->msg_control) {
! 717: #ifdef COMPAT_OLDSOCK
! 718: /*
! 719: * We assume that old recvmsg calls won't receive access
! 720: * rights and other control info, esp. as control info
! 721: * is always optional and those options didn't exist in 4.3.
! 722: * If we receive rights, trim the cmsghdr; anything else
! 723: * is tossed.
! 724: */
! 725: if (control && mp->msg_flags & MSG_COMPAT) {
! 726: if (mtod(control, struct cmsghdr *)->cmsg_level !=
! 727: SOL_SOCKET ||
! 728: mtod(control, struct cmsghdr *)->cmsg_type !=
! 729: SCM_RIGHTS) {
! 730: mp->msg_controllen = 0;
! 731: goto out;
! 732: }
! 733: control->m_len -= sizeof (struct cmsghdr);
! 734: control->m_data += sizeof (struct cmsghdr);
! 735: }
! 736: #endif
! 737: len = mp->msg_controllen;
! 738: if (len <= 0 || control == NULL)
! 739: len = 0;
! 740: else {
! 741: struct mbuf *m = control;
! 742: caddr_t p = mp->msg_control;
! 743:
! 744: do {
! 745: i = m->m_len;
! 746: if (len < i) {
! 747: mp->msg_flags |= MSG_CTRUNC;
! 748: i = len;
! 749: }
! 750: error = copyout(mtod(m, caddr_t), p,
! 751: (unsigned)i);
! 752: if (m->m_next)
! 753: i = ALIGN(i);
! 754: p += i;
! 755: len -= i;
! 756: if (error != 0 || len <= 0)
! 757: break;
! 758: } while ((m = m->m_next) != NULL);
! 759: len = p - (caddr_t)mp->msg_control;
! 760: }
! 761: mp->msg_controllen = len;
! 762: }
! 763: if (!error) {
! 764: fp->f_rxfer++;
! 765: fp->f_rbytes += *retsize;
! 766: }
! 767: out:
! 768: FRELE(fp);
! 769: if (from)
! 770: m_freem(from);
! 771: if (control)
! 772: m_freem(control);
! 773: return (error);
! 774: }
! 775:
! 776: /* ARGSUSED */
! 777: int
! 778: sys_shutdown(struct proc *p, void *v, register_t *retval)
! 779: {
! 780: struct sys_shutdown_args /* {
! 781: syscallarg(int) s;
! 782: syscallarg(int) how;
! 783: } */ *uap = v;
! 784: struct file *fp;
! 785: int error;
! 786:
! 787: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 788: return (error);
! 789: error = soshutdown(fp->f_data, SCARG(uap, how));
! 790: FRELE(fp);
! 791: return (error);
! 792: }
! 793:
! 794: /* ARGSUSED */
! 795: int
! 796: sys_setsockopt(struct proc *p, void *v, register_t *retval)
! 797: {
! 798: struct sys_setsockopt_args /* {
! 799: syscallarg(int) s;
! 800: syscallarg(int) level;
! 801: syscallarg(int) name;
! 802: syscallarg(const void *) val;
! 803: syscallarg(socklen_t) valsize;
! 804: } */ *uap = v;
! 805: struct file *fp;
! 806: struct mbuf *m = NULL;
! 807: int error;
! 808:
! 809: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 810: return (error);
! 811: if (SCARG(uap, valsize) > MCLBYTES) {
! 812: error = EINVAL;
! 813: goto bad;
! 814: }
! 815: if (SCARG(uap, val)) {
! 816: m = m_get(M_WAIT, MT_SOOPTS);
! 817: if (SCARG(uap, valsize) > MLEN) {
! 818: MCLGET(m, M_DONTWAIT);
! 819: if ((m->m_flags & M_EXT) == 0) {
! 820: error = ENOBUFS;
! 821: goto bad;
! 822: }
! 823: }
! 824: if (m == NULL) {
! 825: error = ENOBUFS;
! 826: goto bad;
! 827: }
! 828: error = copyin(SCARG(uap, val), mtod(m, caddr_t),
! 829: SCARG(uap, valsize));
! 830: if (error) {
! 831: goto bad;
! 832: }
! 833: m->m_len = SCARG(uap, valsize);
! 834: }
! 835: error = sosetopt(fp->f_data, SCARG(uap, level),
! 836: SCARG(uap, name), m);
! 837: m = NULL;
! 838: bad:
! 839: if (m)
! 840: m_freem(m);
! 841: FRELE(fp);
! 842: return (error);
! 843: }
! 844:
! 845: /* ARGSUSED */
! 846: int
! 847: sys_getsockopt(struct proc *p, void *v, register_t *retval)
! 848: {
! 849: struct sys_getsockopt_args /* {
! 850: syscallarg(int) s;
! 851: syscallarg(int) level;
! 852: syscallarg(int) name;
! 853: syscallarg(void *) val;
! 854: syscallarg(socklen_t *) avalsize;
! 855: } */ *uap = v;
! 856: struct file *fp;
! 857: struct mbuf *m = NULL;
! 858: socklen_t valsize;
! 859: int error;
! 860:
! 861: if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
! 862: return (error);
! 863: if (SCARG(uap, val)) {
! 864: error = copyin(SCARG(uap, avalsize),
! 865: &valsize, sizeof (valsize));
! 866: if (error)
! 867: goto out;
! 868: } else
! 869: valsize = 0;
! 870: if ((error = sogetopt(fp->f_data, SCARG(uap, level),
! 871: SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
! 872: m != NULL) {
! 873: if (valsize > m->m_len)
! 874: valsize = m->m_len;
! 875: error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
! 876: if (error == 0)
! 877: error = copyout(&valsize,
! 878: SCARG(uap, avalsize), sizeof (valsize));
! 879: }
! 880: out:
! 881: FRELE(fp);
! 882: if (m != NULL)
! 883: (void)m_free(m);
! 884: return (error);
! 885: }
! 886:
! 887: int
! 888: sys_pipe(struct proc *p, void *v, register_t *retval)
! 889: {
! 890: struct sys_pipe_args /* {
! 891: syscallarg(int *) fdp;
! 892: } */ *uap = v;
! 893: int error, fds[2];
! 894: register_t rval[2];
! 895:
! 896: if ((error = sys_opipe(p, v, rval)) != 0)
! 897: return (error);
! 898:
! 899: fds[0] = rval[0];
! 900: fds[1] = rval[1];
! 901: error = copyout(fds, SCARG(uap, fdp), 2 * sizeof (int));
! 902: if (error) {
! 903: fdplock(p->p_fd);
! 904: fdrelease(p, fds[0]);
! 905: fdrelease(p, fds[1]);
! 906: fdpunlock(p->p_fd);
! 907: }
! 908: return (error);
! 909: }
! 910:
! 911: /*
! 912: * Get socket name.
! 913: */
! 914: /* ARGSUSED */
! 915: int
! 916: sys_getsockname(struct proc *p, void *v, register_t *retval)
! 917: {
! 918: struct sys_getsockname_args /* {
! 919: syscallarg(int) fdes;
! 920: syscallarg(struct sockaddr *) asa;
! 921: syscallarg(socklen_t *) alen;
! 922: } */ *uap = v;
! 923: struct file *fp;
! 924: struct socket *so;
! 925: struct mbuf *m = NULL;
! 926: socklen_t len;
! 927: int error;
! 928:
! 929: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
! 930: return (error);
! 931: error = copyin(SCARG(uap, alen), &len, sizeof (len));
! 932: if (error)
! 933: goto bad;
! 934: so = fp->f_data;
! 935: m = m_getclr(M_WAIT, MT_SONAME);
! 936: error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
! 937: if (error)
! 938: goto bad;
! 939: if (len > m->m_len)
! 940: len = m->m_len;
! 941: error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
! 942: if (error == 0)
! 943: error = copyout(&len, SCARG(uap, alen), sizeof (len));
! 944: bad:
! 945: FRELE(fp);
! 946: if (m)
! 947: m_freem(m);
! 948: return (error);
! 949: }
! 950:
! 951: /*
! 952: * Get name of peer for connected socket.
! 953: */
! 954: /* ARGSUSED */
! 955: int
! 956: sys_getpeername(struct proc *p, void *v, register_t *retval)
! 957: {
! 958: struct sys_getpeername_args /* {
! 959: syscallarg(int) fdes;
! 960: syscallarg(struct sockaddr *) asa;
! 961: syscallarg(socklen_t *) alen;
! 962: } */ *uap = v;
! 963: struct file *fp;
! 964: struct socket *so;
! 965: struct mbuf *m = NULL;
! 966: socklen_t len;
! 967: int error;
! 968:
! 969: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
! 970: return (error);
! 971: so = fp->f_data;
! 972: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
! 973: FRELE(fp);
! 974: return (ENOTCONN);
! 975: }
! 976: error = copyin(SCARG(uap, alen), &len, sizeof (len));
! 977: if (error)
! 978: goto bad;
! 979: m = m_getclr(M_WAIT, MT_SONAME);
! 980: error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0);
! 981: if (error)
! 982: goto bad;
! 983: if (len > m->m_len)
! 984: len = m->m_len;
! 985: error = copyout(mtod(m, caddr_t), SCARG(uap, asa), len);
! 986: if (error == 0)
! 987: error = copyout(&len, SCARG(uap, alen), sizeof (len));
! 988: bad:
! 989: FRELE(fp);
! 990: m_freem(m);
! 991: return (error);
! 992: }
! 993:
! 994: /*
! 995: * Get eid of peer for connected socket.
! 996: */
! 997: /* ARGSUSED */
! 998: int
! 999: sys_getpeereid(struct proc *p, void *v, register_t *retval)
! 1000: {
! 1001: struct sys_getpeereid_args /* {
! 1002: syscallarg(int) fdes;
! 1003: syscallarg(uid_t *) euid;
! 1004: syscallarg(gid_t *) egid;
! 1005: } */ *uap = v;
! 1006: struct file *fp;
! 1007: struct socket *so;
! 1008: struct mbuf *m = NULL;
! 1009: struct unpcbid *id;
! 1010: int error;
! 1011:
! 1012: if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0)
! 1013: return (error);
! 1014: so = fp->f_data;
! 1015: if (so->so_proto != pffindtype(AF_LOCAL, SOCK_STREAM)) {
! 1016: FRELE(fp);
! 1017: return (EOPNOTSUPP);
! 1018: }
! 1019: m = m_getclr(M_WAIT, MT_SONAME);
! 1020: if (m == NULL) {
! 1021: error = ENOBUFS;
! 1022: goto bad;
! 1023: }
! 1024: error = (*so->so_proto->pr_usrreq)(so, PRU_PEEREID, 0, m, 0);
! 1025: if (!error && m->m_len != sizeof(struct unpcbid))
! 1026: error = EOPNOTSUPP;
! 1027: if (error)
! 1028: goto bad;
! 1029: id = mtod(m, struct unpcbid *);
! 1030: error = copyout(&(id->unp_euid), SCARG(uap, euid), sizeof(uid_t));
! 1031: if (error == 0)
! 1032: error = copyout(&(id->unp_egid), SCARG(uap, egid), sizeof(gid_t));
! 1033: bad:
! 1034: FRELE(fp);
! 1035: m_freem(m);
! 1036: return (error);
! 1037: }
! 1038:
! 1039: int
! 1040: sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
! 1041: {
! 1042: struct sockaddr *sa;
! 1043: struct mbuf *m;
! 1044: int error;
! 1045:
! 1046: /*
! 1047: * We can't allow socket names > UCHAR_MAX in length, since that
! 1048: * will overflow sa_len. Also, control data more than MCLBYTES in
! 1049: * length is just too much.
! 1050: */
! 1051: if (buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES))
! 1052: return (EINVAL);
! 1053:
! 1054: /* Allocate an mbuf to hold the arguments. */
! 1055: m = m_get(M_WAIT, type);
! 1056: if ((u_int)buflen > MLEN) {
! 1057: MCLGET(m, M_WAITOK);
! 1058: if ((m->m_flags & M_EXT) == 0) {
! 1059: m_free(m);
! 1060: return ENOBUFS;
! 1061: }
! 1062: }
! 1063: m->m_len = buflen;
! 1064: error = copyin(buf, mtod(m, caddr_t), buflen);
! 1065: if (error) {
! 1066: (void) m_free(m);
! 1067: return (error);
! 1068: }
! 1069: *mp = m;
! 1070: if (type == MT_SONAME) {
! 1071: sa = mtod(m, struct sockaddr *);
! 1072: #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
! 1073: if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
! 1074: sa->sa_family = sa->sa_len;
! 1075: #endif
! 1076: sa->sa_len = buflen;
! 1077: }
! 1078: return (0);
! 1079: }
! 1080:
! 1081: int
! 1082: getsock(struct filedesc *fdp, int fdes, struct file **fpp)
! 1083: {
! 1084: struct file *fp;
! 1085:
! 1086: if ((fp = fd_getfile(fdp, fdes)) == NULL)
! 1087: return (EBADF);
! 1088: if (fp->f_type != DTYPE_SOCKET)
! 1089: return (ENOTSOCK);
! 1090: *fpp = fp;
! 1091: FREF(fp);
! 1092:
! 1093: return (0);
! 1094: }
CVSweb