root/kern/uipc_syscalls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_socket
  2. sys_bind
  3. sys_listen
  4. sys_accept
  5. sys_connect
  6. sys_socketpair
  7. sys_sendto
  8. sys_sendmsg
  9. sendit
  10. sys_recvfrom
  11. sys_recvmsg
  12. recvit
  13. sys_shutdown
  14. sys_setsockopt
  15. sys_getsockopt
  16. sys_pipe
  17. sys_getsockname
  18. sys_getpeername
  19. sys_getpeereid
  20. sockargs
  21. getsock

    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 }

/* [<][>][^][v][top][bottom][index][help] */