[BACK]Return to uipc_syscalls.c CVS log [TXT][DIR] Up to [local] / sys / kern

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