The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_usrreq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1982, 1986, 1989, 1991, 1993
    3  *      The Regents of the University of California.
    4  * Copyright 2004-2005 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 4. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/6.2/sys/kern/uipc_usrreq.c 164286 2006-11-14 20:42:41Z cvs2svn $");
   36 
   37 #include "opt_mac.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/domain.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/malloc.h>         /* XXX must be before <sys/file.h> */
   43 #include <sys/eventhandler.h>
   44 #include <sys/file.h>
   45 #include <sys/filedesc.h>
   46 #include <sys/jail.h>
   47 #include <sys/kernel.h>
   48 #include <sys/lock.h>
   49 #include <sys/mac.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/mount.h>
   52 #include <sys/mutex.h>
   53 #include <sys/namei.h>
   54 #include <sys/proc.h>
   55 #include <sys/protosw.h>
   56 #include <sys/resourcevar.h>
   57 #include <sys/socket.h>
   58 #include <sys/socketvar.h>
   59 #include <sys/signalvar.h>
   60 #include <sys/stat.h>
   61 #include <sys/sx.h>
   62 #include <sys/sysctl.h>
   63 #include <sys/systm.h>
   64 #include <sys/taskqueue.h>
   65 #include <sys/un.h>
   66 #include <sys/unpcb.h>
   67 #include <sys/vnode.h>
   68 
   69 #include <vm/uma.h>
   70 
   71 static uma_zone_t unp_zone;
   72 static  unp_gen_t unp_gencnt;
   73 static  u_int unp_count;
   74 
   75 static  struct unp_head unp_shead, unp_dhead;
   76 
   77 /*
   78  * Unix communications domain.
   79  *
   80  * TODO:
   81  *      SEQPACKET, RDM
   82  *      rethink name space problems
   83  *      need a proper out-of-band
   84  *      lock pushdown
   85  */
   86 static const struct     sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL };
   87 static ino_t    unp_ino;                /* prototype for fake inode numbers */
   88 struct mbuf *unp_addsockcred(struct thread *, struct mbuf *);
   89 
   90 /*
   91  * Currently, UNIX domain sockets are protected by a single subsystem lock,
   92  * which covers global data structures and variables, the contents of each
   93  * per-socket unpcb structure, and the so_pcb field in sockets attached to
   94  * the UNIX domain.  This provides for a moderate degree of paralellism, as
   95  * receive operations on UNIX domain sockets do not need to acquire the
   96  * subsystem lock.  Finer grained locking to permit send() without acquiring
   97  * a global lock would be a logical next step.
   98  *
   99  * The UNIX domain socket lock preceds all socket layer locks, including the
  100  * socket lock and socket buffer lock, permitting UNIX domain socket code to
  101  * call into socket support routines without releasing its locks.
  102  *
  103  * Some caution is required in areas where the UNIX domain socket code enters
  104  * VFS in order to create or find rendezvous points.  This results in
  105  * dropping of the UNIX domain socket subsystem lock, acquisition of the
  106  * Giant lock, and potential sleeping.  This increases the chances of races,
  107  * and exposes weaknesses in the socket->protocol API by offering poor
  108  * failure modes.
  109  */
  110 static struct mtx unp_mtx;
  111 #define UNP_LOCK_INIT() \
  112         mtx_init(&unp_mtx, "unp", NULL, MTX_DEF)
  113 #define UNP_LOCK()              mtx_lock(&unp_mtx)
  114 #define UNP_UNLOCK()            mtx_unlock(&unp_mtx)
  115 #define UNP_LOCK_ASSERT()       mtx_assert(&unp_mtx, MA_OWNED)
  116 #define UNP_UNLOCK_ASSERT()     mtx_assert(&unp_mtx, MA_NOTOWNED)
  117 
  118 /*
  119  * Garbage collection of cyclic file descriptor/socket references occurs
  120  * asynchronously in a taskqueue context in order to avoid recursion and
  121  * reentrance in the UNIX domain socket, file descriptor, and socket layer
  122  * code.  See unp_gc() for a full description.
  123  */
  124 static struct task      unp_gc_task;
  125 
  126 static int     unp_attach(struct socket *);
  127 static void    unp_detach(struct unpcb *);
  128 static int     unp_bind(struct unpcb *,struct sockaddr *, struct thread *);
  129 static int     unp_connect(struct socket *,struct sockaddr *, struct thread *);
  130 static int     unp_connect2(struct socket *so, struct socket *so2, int);
  131 static void    unp_disconnect(struct unpcb *);
  132 static void    unp_shutdown(struct unpcb *);
  133 static void    unp_drop(struct unpcb *, int);
  134 static void    unp_gc(__unused void *, int);
  135 static void    unp_scan(struct mbuf *, void (*)(struct file *));
  136 static void    unp_mark(struct file *);
  137 static void    unp_discard(struct file *);
  138 static void    unp_freerights(struct file **, int);
  139 static int     unp_internalize(struct mbuf **, struct thread *);
  140 static int     unp_listen(struct socket *, struct unpcb *, struct thread *);
  141 
  142 static int
  143 uipc_abort(struct socket *so)
  144 {
  145         struct unpcb *unp;
  146 
  147         UNP_LOCK();
  148         unp = sotounpcb(so);
  149         if (unp == NULL) {
  150                 UNP_UNLOCK();
  151                 return (EINVAL);
  152         }
  153         unp_drop(unp, ECONNABORTED);
  154         unp_detach(unp);
  155         UNP_UNLOCK_ASSERT();
  156         ACCEPT_LOCK();
  157         SOCK_LOCK(so);
  158         sotryfree(so);
  159         return (0);
  160 }
  161 
  162 static int
  163 uipc_accept(struct socket *so, struct sockaddr **nam)
  164 {
  165         struct unpcb *unp;
  166         const struct sockaddr *sa;
  167 
  168         /*
  169          * Pass back name of connected socket,
  170          * if it was bound and we are still connected
  171          * (our peer may have closed already!).
  172          */
  173         *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
  174         UNP_LOCK();
  175         unp = sotounpcb(so);
  176         if (unp == NULL) {
  177                 UNP_UNLOCK();
  178                 free(*nam, M_SONAME);
  179                 *nam = NULL;
  180                 return (EINVAL);
  181         }
  182         if (unp->unp_conn != NULL && unp->unp_conn->unp_addr != NULL)
  183                 sa = (struct sockaddr *) unp->unp_conn->unp_addr;
  184         else
  185                 sa = &sun_noname;
  186         bcopy(sa, *nam, sa->sa_len);
  187         UNP_UNLOCK();
  188         return (0);
  189 }
  190 
  191 static int
  192 uipc_attach(struct socket *so, int proto, struct thread *td)
  193 {
  194         struct unpcb *unp = sotounpcb(so);
  195 
  196         if (unp != NULL)
  197                 return (EISCONN);
  198         return (unp_attach(so));
  199 }
  200 
  201 static int
  202 uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  203 {
  204         struct unpcb *unp;
  205         int error;
  206 
  207         UNP_LOCK();
  208         unp = sotounpcb(so);
  209         if (unp == NULL) {
  210                 UNP_UNLOCK();
  211                 return (EINVAL);
  212         }
  213         error = unp_bind(unp, nam, td);
  214         UNP_UNLOCK();
  215         return (error);
  216 }
  217 
  218 static int
  219 uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  220 {
  221         struct unpcb *unp;
  222         int error;
  223 
  224         KASSERT(td == curthread, ("uipc_connect: td != curthread"));
  225 
  226         UNP_LOCK();
  227         unp = sotounpcb(so);
  228         if (unp == NULL) {
  229                 UNP_UNLOCK();
  230                 return (EINVAL);
  231         }
  232         error = unp_connect(so, nam, td);
  233         UNP_UNLOCK();
  234         return (error);
  235 }
  236 
  237 int
  238 uipc_connect2(struct socket *so1, struct socket *so2)
  239 {
  240         struct unpcb *unp;
  241         int error;
  242 
  243         UNP_LOCK();
  244         unp = sotounpcb(so1);
  245         if (unp == NULL) {
  246                 UNP_UNLOCK();
  247                 return (EINVAL);
  248         }
  249         error = unp_connect2(so1, so2, PRU_CONNECT2);
  250         UNP_UNLOCK();
  251         return (error);
  252 }
  253 
  254 /* control is EOPNOTSUPP */
  255 
  256 static int
  257 uipc_detach(struct socket *so)
  258 {
  259         struct unpcb *unp;
  260 
  261         UNP_LOCK();
  262         unp = sotounpcb(so);
  263         if (unp == NULL) {
  264                 UNP_UNLOCK();
  265                 return (EINVAL);
  266         }
  267         unp_detach(unp);
  268         UNP_UNLOCK_ASSERT();
  269         return (0);
  270 }
  271 
  272 static int
  273 uipc_disconnect(struct socket *so)
  274 {
  275         struct unpcb *unp;
  276 
  277         UNP_LOCK();
  278         unp = sotounpcb(so);
  279         if (unp == NULL) {
  280                 UNP_UNLOCK();
  281                 return (EINVAL);
  282         }
  283         unp_disconnect(unp);
  284         UNP_UNLOCK();
  285         return (0);
  286 }
  287 
  288 static int
  289 uipc_listen(struct socket *so, struct thread *td)
  290 {
  291         struct unpcb *unp;
  292         int error;
  293 
  294         UNP_LOCK();
  295         unp = sotounpcb(so);
  296         if (unp == NULL || unp->unp_vnode == NULL) {
  297                 UNP_UNLOCK();
  298                 return (EINVAL);
  299         }
  300         error = unp_listen(so, unp, td);
  301         UNP_UNLOCK();
  302         return (error);
  303 }
  304 
  305 static int
  306 uipc_peeraddr(struct socket *so, struct sockaddr **nam)
  307 {
  308         struct unpcb *unp;
  309         const struct sockaddr *sa;
  310 
  311         *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
  312         UNP_LOCK();
  313         unp = sotounpcb(so);
  314         if (unp == NULL) {
  315                 UNP_UNLOCK();
  316                 free(*nam, M_SONAME);
  317                 *nam = NULL;
  318                 return (EINVAL);
  319         }
  320         if (unp->unp_conn != NULL && unp->unp_conn->unp_addr!= NULL)
  321                 sa = (struct sockaddr *) unp->unp_conn->unp_addr;
  322         else {
  323                 /*
  324                  * XXX: It seems that this test always fails even when
  325                  * connection is established.  So, this else clause is
  326                  * added as workaround to return PF_LOCAL sockaddr.
  327                  */
  328                 sa = &sun_noname;
  329         }
  330         bcopy(sa, *nam, sa->sa_len);
  331         UNP_UNLOCK();
  332         return (0);
  333 }
  334 
  335 static int
  336 uipc_rcvd(struct socket *so, int flags)
  337 {
  338         struct unpcb *unp;
  339         struct socket *so2;
  340         u_long newhiwat;
  341 
  342         UNP_LOCK();
  343         unp = sotounpcb(so);
  344         if (unp == NULL) {
  345                 UNP_UNLOCK();
  346                 return (EINVAL);
  347         }
  348         switch (so->so_type) {
  349         case SOCK_DGRAM:
  350                 panic("uipc_rcvd DGRAM?");
  351                 /*NOTREACHED*/
  352 
  353         case SOCK_STREAM:
  354                 if (unp->unp_conn == NULL)
  355                         break;
  356                 so2 = unp->unp_conn->unp_socket;
  357                 SOCKBUF_LOCK(&so2->so_snd);
  358                 SOCKBUF_LOCK(&so->so_rcv);
  359                 /*
  360                  * Adjust backpressure on sender
  361                  * and wakeup any waiting to write.
  362                  */
  363                 so2->so_snd.sb_mbmax += unp->unp_mbcnt - so->so_rcv.sb_mbcnt;
  364                 unp->unp_mbcnt = so->so_rcv.sb_mbcnt;
  365                 newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc -
  366                     so->so_rcv.sb_cc;
  367                 (void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat,
  368                     newhiwat, RLIM_INFINITY);
  369                 unp->unp_cc = so->so_rcv.sb_cc;
  370                 SOCKBUF_UNLOCK(&so->so_rcv);
  371                 sowwakeup_locked(so2);
  372                 break;
  373 
  374         default:
  375                 panic("uipc_rcvd unknown socktype");
  376         }
  377         UNP_UNLOCK();
  378         return (0);
  379 }
  380 
  381 /* pru_rcvoob is EOPNOTSUPP */
  382 
  383 static int
  384 uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
  385     struct mbuf *control, struct thread *td)
  386 {
  387         int error = 0;
  388         struct unpcb *unp;
  389         struct socket *so2;
  390         u_long newhiwat;
  391 
  392         unp = sotounpcb(so);
  393         if (unp == NULL) {
  394                 error = EINVAL;
  395                 goto release;
  396         }
  397         if (flags & PRUS_OOB) {
  398                 error = EOPNOTSUPP;
  399                 goto release;
  400         }
  401 
  402         if (control != NULL && (error = unp_internalize(&control, td)))
  403                 goto release;
  404 
  405         UNP_LOCK();
  406         unp = sotounpcb(so);
  407         if (unp == NULL) {
  408                 UNP_UNLOCK();
  409                 error = EINVAL;
  410                 goto dispose_release;
  411         }
  412 
  413         switch (so->so_type) {
  414         case SOCK_DGRAM:
  415         {
  416                 const struct sockaddr *from;
  417 
  418                 if (nam != NULL) {
  419                         if (unp->unp_conn != NULL) {
  420                                 error = EISCONN;
  421                                 break;
  422                         }
  423                         error = unp_connect(so, nam, td);
  424                         if (error)
  425                                 break;
  426                 } else {
  427                         if (unp->unp_conn == NULL) {
  428                                 error = ENOTCONN;
  429                                 break;
  430                         }
  431                 }
  432                 so2 = unp->unp_conn->unp_socket;
  433                 if (unp->unp_addr != NULL)
  434                         from = (struct sockaddr *)unp->unp_addr;
  435                 else
  436                         from = &sun_noname;
  437                 if (unp->unp_conn->unp_flags & UNP_WANTCRED)
  438                         control = unp_addsockcred(td, control);
  439                 SOCKBUF_LOCK(&so2->so_rcv);
  440                 if (sbappendaddr_locked(&so2->so_rcv, from, m, control)) {
  441                         sorwakeup_locked(so2);
  442                         m = NULL;
  443                         control = NULL;
  444                 } else {
  445                         SOCKBUF_UNLOCK(&so2->so_rcv);
  446                         error = ENOBUFS;
  447                 }
  448                 if (nam != NULL)
  449                         unp_disconnect(unp);
  450                 break;
  451         }
  452 
  453         case SOCK_STREAM:
  454                 /* Connect if not connected yet. */
  455                 /*
  456                  * Note: A better implementation would complain
  457                  * if not equal to the peer's address.
  458                  */
  459                 if ((so->so_state & SS_ISCONNECTED) == 0) {
  460                         if (nam != NULL) {
  461                                 error = unp_connect(so, nam, td);
  462                                 if (error)
  463                                         break;  /* XXX */
  464                         } else {
  465                                 error = ENOTCONN;
  466                                 break;
  467                         }
  468                 }
  469 
  470                 SOCKBUF_LOCK(&so->so_snd);
  471                 if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
  472                         SOCKBUF_UNLOCK(&so->so_snd);
  473                         error = EPIPE;
  474                         break;
  475                 }
  476                 if (unp->unp_conn == NULL)
  477                         panic("uipc_send connected but no connection?");
  478                 so2 = unp->unp_conn->unp_socket;
  479                 SOCKBUF_LOCK(&so2->so_rcv);
  480                 if (unp->unp_conn->unp_flags & UNP_WANTCRED) {
  481                         /*
  482                          * Credentials are passed only once on
  483                          * SOCK_STREAM.
  484                          */
  485                         unp->unp_conn->unp_flags &= ~UNP_WANTCRED;
  486                         control = unp_addsockcred(td, control);
  487                 }
  488                 /*
  489                  * Send to paired receive port, and then reduce
  490                  * send buffer hiwater marks to maintain backpressure.
  491                  * Wake up readers.
  492                  */
  493                 if (control != NULL) {
  494                         if (sbappendcontrol_locked(&so2->so_rcv, m, control))
  495                                 control = NULL;
  496                 } else {
  497                         sbappend_locked(&so2->so_rcv, m);
  498                 }
  499                 so->so_snd.sb_mbmax -=
  500                         so2->so_rcv.sb_mbcnt - unp->unp_conn->unp_mbcnt;
  501                 unp->unp_conn->unp_mbcnt = so2->so_rcv.sb_mbcnt;
  502                 newhiwat = so->so_snd.sb_hiwat -
  503                     (so2->so_rcv.sb_cc - unp->unp_conn->unp_cc);
  504                 (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat,
  505                     newhiwat, RLIM_INFINITY);
  506                 SOCKBUF_UNLOCK(&so->so_snd);
  507                 unp->unp_conn->unp_cc = so2->so_rcv.sb_cc;
  508                 sorwakeup_locked(so2);
  509                 m = NULL;
  510                 break;
  511 
  512         default:
  513                 panic("uipc_send unknown socktype");
  514         }
  515 
  516         /*
  517          * SEND_EOF is equivalent to a SEND followed by
  518          * a SHUTDOWN.
  519          */
  520         if (flags & PRUS_EOF) {
  521                 socantsendmore(so);
  522                 unp_shutdown(unp);
  523         }
  524         UNP_UNLOCK();
  525 
  526 dispose_release:
  527         if (control != NULL && error != 0)
  528                 unp_dispose(control);
  529 
  530 release:
  531         if (control != NULL)
  532                 m_freem(control);
  533         if (m != NULL)
  534                 m_freem(m);
  535         return (error);
  536 }
  537 
  538 static int
  539 uipc_sense(struct socket *so, struct stat *sb)
  540 {
  541         struct unpcb *unp;
  542         struct socket *so2;
  543 
  544         UNP_LOCK();
  545         unp = sotounpcb(so);
  546         if (unp == NULL) {
  547                 UNP_UNLOCK();
  548                 return (EINVAL);
  549         }
  550         sb->st_blksize = so->so_snd.sb_hiwat;
  551         if (so->so_type == SOCK_STREAM && unp->unp_conn != NULL) {
  552                 so2 = unp->unp_conn->unp_socket;
  553                 sb->st_blksize += so2->so_rcv.sb_cc;
  554         }
  555         sb->st_dev = NODEV;
  556         if (unp->unp_ino == 0)
  557                 unp->unp_ino = (++unp_ino == 0) ? ++unp_ino : unp_ino;
  558         sb->st_ino = unp->unp_ino;
  559         UNP_UNLOCK();
  560         return (0);
  561 }
  562 
  563 static int
  564 uipc_shutdown(struct socket *so)
  565 {
  566         struct unpcb *unp;
  567 
  568         UNP_LOCK();
  569         unp = sotounpcb(so);
  570         if (unp == NULL) {
  571                 UNP_UNLOCK();
  572                 return (EINVAL);
  573         }
  574         socantsendmore(so);
  575         unp_shutdown(unp);
  576         UNP_UNLOCK();
  577         return (0);
  578 }
  579 
  580 static int
  581 uipc_sockaddr(struct socket *so, struct sockaddr **nam)
  582 {
  583         struct unpcb *unp;
  584         const struct sockaddr *sa;
  585 
  586         *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
  587         UNP_LOCK();
  588         unp = sotounpcb(so);
  589         if (unp == NULL) {
  590                 UNP_UNLOCK();
  591                 free(*nam, M_SONAME);
  592                 *nam = NULL;
  593                 return (EINVAL);
  594         }
  595         if (unp->unp_addr != NULL)
  596                 sa = (struct sockaddr *) unp->unp_addr;
  597         else
  598                 sa = &sun_noname;
  599         bcopy(sa, *nam, sa->sa_len);
  600         UNP_UNLOCK();
  601         return (0);
  602 }
  603 
  604 struct pr_usrreqs uipc_usrreqs = {
  605         .pru_abort =            uipc_abort,
  606         .pru_accept =           uipc_accept,
  607         .pru_attach =           uipc_attach,
  608         .pru_bind =             uipc_bind,
  609         .pru_connect =          uipc_connect,
  610         .pru_connect2 =         uipc_connect2,
  611         .pru_detach =           uipc_detach,
  612         .pru_disconnect =       uipc_disconnect,
  613         .pru_listen =           uipc_listen,
  614         .pru_peeraddr =         uipc_peeraddr,
  615         .pru_rcvd =             uipc_rcvd,
  616         .pru_send =             uipc_send,
  617         .pru_sense =            uipc_sense,
  618         .pru_shutdown =         uipc_shutdown,
  619         .pru_sockaddr =         uipc_sockaddr,
  620         .pru_sosend =           sosend,
  621         .pru_soreceive =        soreceive,
  622         .pru_sopoll =           sopoll,
  623 };
  624 
  625 int
  626 uipc_ctloutput(struct socket *so, struct sockopt *sopt)
  627 {
  628         struct unpcb *unp;
  629         struct xucred xu;
  630         int error, optval;
  631 
  632         if (sopt->sopt_level != 0)
  633                 return (EINVAL);
  634 
  635         UNP_LOCK();
  636         unp = sotounpcb(so);
  637         if (unp == NULL) {
  638                 UNP_UNLOCK();
  639                 return (EINVAL);
  640         }
  641         error = 0;
  642 
  643         switch (sopt->sopt_dir) {
  644         case SOPT_GET:
  645                 switch (sopt->sopt_name) {
  646                 case LOCAL_PEERCRED:
  647                         if (unp->unp_flags & UNP_HAVEPC)
  648                                 xu = unp->unp_peercred;
  649                         else {
  650                                 if (so->so_type == SOCK_STREAM)
  651                                         error = ENOTCONN;
  652                                 else
  653                                         error = EINVAL;
  654                         }
  655                         if (error == 0)
  656                                 error = sooptcopyout(sopt, &xu, sizeof(xu));
  657                         break;
  658                 case LOCAL_CREDS:
  659                         optval = unp->unp_flags & UNP_WANTCRED ? 1 : 0;
  660                         error = sooptcopyout(sopt, &optval, sizeof(optval));
  661                         break;
  662                 case LOCAL_CONNWAIT:
  663                         optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0;
  664                         error = sooptcopyout(sopt, &optval, sizeof(optval));
  665                         break;
  666                 default:
  667                         error = EOPNOTSUPP;
  668                         break;
  669                 }
  670                 break;
  671         case SOPT_SET:
  672                 switch (sopt->sopt_name) {
  673                 case LOCAL_CREDS:
  674                 case LOCAL_CONNWAIT:
  675                         error = sooptcopyin(sopt, &optval, sizeof(optval),
  676                                             sizeof(optval));
  677                         if (error)
  678                                 break;
  679 
  680 #define OPTSET(bit) \
  681         if (optval) \
  682                 unp->unp_flags |= bit; \
  683         else \
  684                 unp->unp_flags &= ~bit;
  685 
  686                         switch (sopt->sopt_name) {
  687                         case LOCAL_CREDS:
  688                                 OPTSET(UNP_WANTCRED);
  689                                 break;
  690                         case LOCAL_CONNWAIT:
  691                                 OPTSET(UNP_CONNWAIT);
  692                                 break;
  693                         default:
  694                                 break;
  695                         }
  696                         break;
  697 #undef  OPTSET
  698                 default:
  699                         error = ENOPROTOOPT;
  700                         break;
  701                 }
  702                 break;
  703         default:
  704                 error = EOPNOTSUPP;
  705                 break;
  706         }
  707         UNP_UNLOCK();
  708         return (error);
  709 }
  710 
  711 /*
  712  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
  713  * for stream sockets, although the total for sender and receiver is
  714  * actually only PIPSIZ.
  715  * Datagram sockets really use the sendspace as the maximum datagram size,
  716  * and don't really want to reserve the sendspace.  Their recvspace should
  717  * be large enough for at least one max-size datagram plus address.
  718  */
  719 #ifndef PIPSIZ
  720 #define PIPSIZ  8192
  721 #endif
  722 static u_long   unpst_sendspace = PIPSIZ;
  723 static u_long   unpst_recvspace = PIPSIZ;
  724 static u_long   unpdg_sendspace = 2*1024;       /* really max datagram size */
  725 static u_long   unpdg_recvspace = 4*1024;
  726 
  727 static int      unp_rights;                     /* file descriptors in flight */
  728 
  729 SYSCTL_DECL(_net_local_stream);
  730 SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW,
  731            &unpst_sendspace, 0, "");
  732 SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW,
  733            &unpst_recvspace, 0, "");
  734 SYSCTL_DECL(_net_local_dgram);
  735 SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW,
  736            &unpdg_sendspace, 0, "");
  737 SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW,
  738            &unpdg_recvspace, 0, "");
  739 SYSCTL_DECL(_net_local);
  740 SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, "");
  741 
  742 static int
  743 unp_attach(struct socket *so)
  744 {
  745         struct unpcb *unp;
  746         int error;
  747 
  748         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  749                 switch (so->so_type) {
  750 
  751                 case SOCK_STREAM:
  752                         error = soreserve(so, unpst_sendspace, unpst_recvspace);
  753                         break;
  754 
  755                 case SOCK_DGRAM:
  756                         error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
  757                         break;
  758 
  759                 default:
  760                         panic("unp_attach");
  761                 }
  762                 if (error)
  763                         return (error);
  764         }
  765         unp = uma_zalloc(unp_zone, M_WAITOK | M_ZERO);
  766         if (unp == NULL)
  767                 return (ENOBUFS);
  768         LIST_INIT(&unp->unp_refs);
  769         unp->unp_socket = so;
  770         so->so_pcb = unp;
  771 
  772         UNP_LOCK();
  773         unp->unp_gencnt = ++unp_gencnt;
  774         unp_count++;
  775         LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead
  776                          : &unp_shead, unp, unp_link);
  777         UNP_UNLOCK();
  778 
  779         return (0);
  780 }
  781 
  782 static void
  783 unp_detach(struct unpcb *unp)
  784 {
  785         struct vnode *vp;
  786         int local_unp_rights;
  787 
  788         UNP_LOCK_ASSERT();
  789 
  790         LIST_REMOVE(unp, unp_link);
  791         unp->unp_gencnt = ++unp_gencnt;
  792         --unp_count;
  793         if ((vp = unp->unp_vnode) != NULL) {
  794                 /*
  795                  * XXXRW: should v_socket be frobbed only while holding
  796                  * Giant?
  797                  */
  798                 unp->unp_vnode->v_socket = NULL;
  799                 unp->unp_vnode = NULL;
  800         }
  801         if (unp->unp_conn != NULL)
  802                 unp_disconnect(unp);
  803         while (!LIST_EMPTY(&unp->unp_refs)) {
  804                 struct unpcb *ref = LIST_FIRST(&unp->unp_refs);
  805                 unp_drop(ref, ECONNRESET);
  806         }
  807         soisdisconnected(unp->unp_socket);
  808         unp->unp_socket->so_pcb = NULL;
  809         local_unp_rights = unp_rights;
  810         UNP_UNLOCK();
  811         if (unp->unp_addr != NULL)
  812                 FREE(unp->unp_addr, M_SONAME);
  813         uma_zfree(unp_zone, unp);
  814         if (vp) {
  815                 int vfslocked;
  816 
  817                 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
  818                 vrele(vp);
  819                 VFS_UNLOCK_GIANT(vfslocked);
  820         }
  821         if (local_unp_rights)
  822                 taskqueue_enqueue(taskqueue_thread, &unp_gc_task);
  823 }
  824 
  825 static int
  826 unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td)
  827 {
  828         struct sockaddr_un *soun = (struct sockaddr_un *)nam;
  829         struct vnode *vp;
  830         struct mount *mp;
  831         struct vattr vattr;
  832         int error, namelen;
  833         struct nameidata nd;
  834         char *buf;
  835 
  836         UNP_LOCK_ASSERT();
  837 
  838         /*
  839          * XXXRW: This test-and-set of unp_vnode is non-atomic; the
  840          * unlocked read here is fine, but the value of unp_vnode needs
  841          * to be tested again after we do all the lookups to see if the
  842          * pcb is still unbound?
  843          */
  844         if (unp->unp_vnode != NULL)
  845                 return (EINVAL);
  846 
  847         namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
  848         if (namelen <= 0)
  849                 return (EINVAL);
  850 
  851         UNP_UNLOCK();
  852 
  853         buf = malloc(namelen + 1, M_TEMP, M_WAITOK);
  854         strlcpy(buf, soun->sun_path, namelen + 1);
  855 
  856         mtx_lock(&Giant);
  857 restart:
  858         mtx_assert(&Giant, MA_OWNED);
  859         NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME, UIO_SYSSPACE,
  860             buf, td);
  861 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
  862         error = namei(&nd);
  863         if (error)
  864                 goto done;
  865         vp = nd.ni_vp;
  866         if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
  867                 NDFREE(&nd, NDF_ONLY_PNBUF);
  868                 if (nd.ni_dvp == vp)
  869                         vrele(nd.ni_dvp);
  870                 else
  871                         vput(nd.ni_dvp);
  872                 if (vp != NULL) {
  873                         vrele(vp);
  874                         error = EADDRINUSE;
  875                         goto done;
  876                 }
  877                 error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);
  878                 if (error)
  879                         goto done;
  880                 goto restart;
  881         }
  882         VATTR_NULL(&vattr);
  883         vattr.va_type = VSOCK;
  884         vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask);
  885 #ifdef MAC
  886         error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
  887             &vattr);
  888 #endif
  889         if (error == 0) {
  890                 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
  891                 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
  892         }
  893         NDFREE(&nd, NDF_ONLY_PNBUF);
  894         vput(nd.ni_dvp);
  895         if (error) {
  896                 vn_finished_write(mp);
  897                 goto done;
  898         }
  899         vp = nd.ni_vp;
  900         ASSERT_VOP_LOCKED(vp, "unp_bind");
  901         soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK);
  902         UNP_LOCK();
  903         vp->v_socket = unp->unp_socket;
  904         unp->unp_vnode = vp;
  905         unp->unp_addr = soun;
  906         UNP_UNLOCK();
  907         VOP_UNLOCK(vp, 0, td);
  908         vn_finished_write(mp);
  909 done:
  910         mtx_unlock(&Giant);
  911         free(buf, M_TEMP);
  912         UNP_LOCK();
  913         return (error);
  914 }
  915 
  916 static int
  917 unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  918 {
  919         struct sockaddr_un *soun = (struct sockaddr_un *)nam;
  920         struct vnode *vp;
  921         struct socket *so2, *so3;
  922         struct unpcb *unp, *unp2, *unp3;
  923         int error, len;
  924         struct nameidata nd;
  925         char buf[SOCK_MAXADDRLEN];
  926         struct sockaddr *sa;
  927 
  928         UNP_LOCK_ASSERT();
  929         unp = sotounpcb(so);
  930 
  931         len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
  932         if (len <= 0)
  933                 return (EINVAL);
  934         strlcpy(buf, soun->sun_path, len + 1);
  935         UNP_UNLOCK();
  936         sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
  937         mtx_lock(&Giant);
  938         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, td);
  939         error = namei(&nd);
  940         if (error)
  941                 vp = NULL;
  942         else
  943                 vp = nd.ni_vp;
  944         ASSERT_VOP_LOCKED(vp, "unp_connect");
  945         NDFREE(&nd, NDF_ONLY_PNBUF);
  946         if (error)
  947                 goto bad;
  948 
  949         if (vp->v_type != VSOCK) {
  950                 error = ENOTSOCK;
  951                 goto bad;
  952         }
  953         error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td);
  954         if (error)
  955                 goto bad;
  956         mtx_unlock(&Giant);
  957         UNP_LOCK();
  958         unp = sotounpcb(so);
  959         if (unp == NULL) {
  960                 error = EINVAL;
  961                 goto bad2;
  962         }
  963         so2 = vp->v_socket;
  964         if (so2 == NULL) {
  965                 error = ECONNREFUSED;
  966                 goto bad2;
  967         }
  968         if (so->so_type != so2->so_type) {
  969                 error = EPROTOTYPE;
  970                 goto bad2;
  971         }
  972         if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  973                 if (so2->so_options & SO_ACCEPTCONN) {
  974                         /*
  975                          * NB: drop locks here so unp_attach is entered
  976                          *     w/o locks; this avoids a recursive lock
  977                          *     of the head and holding sleep locks across
  978                          *     a (potentially) blocking malloc.
  979                          */
  980                         UNP_UNLOCK();
  981                         so3 = sonewconn(so2, 0);
  982                         UNP_LOCK();
  983                 } else
  984                         so3 = NULL;
  985                 if (so3 == NULL) {
  986                         error = ECONNREFUSED;
  987                         goto bad2;
  988                 }
  989                 unp = sotounpcb(so);
  990                 unp2 = sotounpcb(so2);
  991                 unp3 = sotounpcb(so3);
  992                 if (unp2->unp_addr != NULL) {
  993                         bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
  994                         unp3->unp_addr = (struct sockaddr_un *) sa;
  995                         sa = NULL;
  996                 }
  997                 /*
  998                  * unp_peercred management:
  999                  *
 1000                  * The connecter's (client's) credentials are copied
 1001                  * from its process structure at the time of connect()
 1002                  * (which is now).
 1003                  */
 1004                 cru2x(td->td_ucred, &unp3->unp_peercred);
 1005                 unp3->unp_flags |= UNP_HAVEPC;
 1006                 /*
 1007                  * The receiver's (server's) credentials are copied
 1008                  * from the unp_peercred member of socket on which the
 1009                  * former called listen(); unp_listen() cached that
 1010                  * process's credentials at that time so we can use
 1011                  * them now.
 1012                  */
 1013                 KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
 1014                     ("unp_connect: listener without cached peercred"));
 1015                 memcpy(&unp->unp_peercred, &unp2->unp_peercred,
 1016                     sizeof(unp->unp_peercred));
 1017                 unp->unp_flags |= UNP_HAVEPC;
 1018                 if (unp2->unp_flags & UNP_WANTCRED)
 1019                         unp3->unp_flags |= UNP_WANTCRED;
 1020 #ifdef MAC
 1021                 SOCK_LOCK(so);
 1022                 mac_set_socket_peer_from_socket(so, so3);
 1023                 mac_set_socket_peer_from_socket(so3, so);
 1024                 SOCK_UNLOCK(so);
 1025 #endif
 1026 
 1027                 so2 = so3;
 1028         }
 1029         error = unp_connect2(so, so2, PRU_CONNECT);
 1030 bad2:
 1031         UNP_UNLOCK();
 1032         mtx_lock(&Giant);
 1033 bad:
 1034         mtx_assert(&Giant, MA_OWNED);
 1035         if (vp != NULL)
 1036                 vput(vp);
 1037         mtx_unlock(&Giant);
 1038         free(sa, M_SONAME);
 1039         UNP_LOCK();
 1040         return (error);
 1041 }
 1042 
 1043 static int
 1044 unp_connect2(struct socket *so, struct socket *so2, int req)
 1045 {
 1046         struct unpcb *unp = sotounpcb(so);
 1047         struct unpcb *unp2;
 1048 
 1049         UNP_LOCK_ASSERT();
 1050 
 1051         if (so2->so_type != so->so_type)
 1052                 return (EPROTOTYPE);
 1053         unp2 = sotounpcb(so2);
 1054         unp->unp_conn = unp2;
 1055         switch (so->so_type) {
 1056 
 1057         case SOCK_DGRAM:
 1058                 LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
 1059                 soisconnected(so);
 1060                 break;
 1061 
 1062         case SOCK_STREAM:
 1063                 unp2->unp_conn = unp;
 1064                 if (req == PRU_CONNECT &&
 1065                     ((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT))
 1066                         soisconnecting(so);
 1067                 else
 1068                         soisconnected(so);
 1069                 soisconnected(so2);
 1070                 break;
 1071 
 1072         default:
 1073                 panic("unp_connect2");
 1074         }
 1075         return (0);
 1076 }
 1077 
 1078 static void
 1079 unp_disconnect(struct unpcb *unp)
 1080 {
 1081         struct unpcb *unp2 = unp->unp_conn;
 1082         struct socket *so;
 1083 
 1084         UNP_LOCK_ASSERT();
 1085 
 1086         if (unp2 == NULL)
 1087                 return;
 1088         unp->unp_conn = NULL;
 1089         switch (unp->unp_socket->so_type) {
 1090 
 1091         case SOCK_DGRAM:
 1092                 LIST_REMOVE(unp, unp_reflink);
 1093                 so = unp->unp_socket;
 1094                 SOCK_LOCK(so);
 1095                 so->so_state &= ~SS_ISCONNECTED;
 1096                 SOCK_UNLOCK(so);
 1097                 break;
 1098 
 1099         case SOCK_STREAM:
 1100                 soisdisconnected(unp->unp_socket);
 1101                 unp2->unp_conn = NULL;
 1102                 soisdisconnected(unp2->unp_socket);
 1103                 break;
 1104         }
 1105 }
 1106 
 1107 #ifdef notdef
 1108 void
 1109 unp_abort(struct unpcb *unp)
 1110 {
 1111 
 1112         unp_detach(unp);
 1113         UNP_UNLOCK_ASSERT();
 1114 }
 1115 #endif
 1116 
 1117 /*
 1118  * unp_pcblist() assumes that UNIX domain socket memory is never reclaimed
 1119  * by the zone (UMA_ZONE_NOFREE), and as such potentially stale pointers
 1120  * are safe to reference.  It first scans the list of struct unpcb's to
 1121  * generate a pointer list, then it rescans its list one entry at a time to
 1122  * externalize and copyout.  It checks the generation number to see if a
 1123  * struct unpcb has been reused, and will skip it if so.
 1124  */
 1125 static int
 1126 unp_pcblist(SYSCTL_HANDLER_ARGS)
 1127 {
 1128         int error, i, n;
 1129         struct unpcb *unp, **unp_list;
 1130         unp_gen_t gencnt;
 1131         struct xunpgen *xug;
 1132         struct unp_head *head;
 1133         struct xunpcb *xu;
 1134 
 1135         head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
 1136 
 1137         /*
 1138          * The process of preparing the PCB list is too time-consuming and
 1139          * resource-intensive to repeat twice on every request.
 1140          */
 1141         if (req->oldptr == NULL) {
 1142                 n = unp_count;
 1143                 req->oldidx = 2 * (sizeof *xug)
 1144                         + (n + n/8) * sizeof(struct xunpcb);
 1145                 return (0);
 1146         }
 1147 
 1148         if (req->newptr != NULL)
 1149                 return (EPERM);
 1150 
 1151         /*
 1152          * OK, now we're committed to doing something.
 1153          */
 1154         xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK);
 1155         UNP_LOCK();
 1156         gencnt = unp_gencnt;
 1157         n = unp_count;
 1158         UNP_UNLOCK();
 1159 
 1160         xug->xug_len = sizeof *xug;
 1161         xug->xug_count = n;
 1162         xug->xug_gen = gencnt;
 1163         xug->xug_sogen = so_gencnt;
 1164         error = SYSCTL_OUT(req, xug, sizeof *xug);
 1165         if (error) {
 1166                 free(xug, M_TEMP);
 1167                 return (error);
 1168         }
 1169 
 1170         unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK);
 1171 
 1172         UNP_LOCK();
 1173         for (unp = LIST_FIRST(head), i = 0; unp && i < n;
 1174              unp = LIST_NEXT(unp, unp_link)) {
 1175                 if (unp->unp_gencnt <= gencnt) {
 1176                         if (cr_cansee(req->td->td_ucred,
 1177                             unp->unp_socket->so_cred))
 1178                                 continue;
 1179                         unp_list[i++] = unp;
 1180                 }
 1181         }
 1182         UNP_UNLOCK();
 1183         n = i;                  /* in case we lost some during malloc */
 1184 
 1185         error = 0;
 1186         xu = malloc(sizeof(*xu), M_TEMP, M_WAITOK | M_ZERO);
 1187         for (i = 0; i < n; i++) {
 1188                 unp = unp_list[i];
 1189                 if (unp->unp_gencnt <= gencnt) {
 1190                         xu->xu_len = sizeof *xu;
 1191                         xu->xu_unpp = unp;
 1192                         /*
 1193                          * XXX - need more locking here to protect against
 1194                          * connect/disconnect races for SMP.
 1195                          */
 1196                         if (unp->unp_addr != NULL)
 1197                                 bcopy(unp->unp_addr, &xu->xu_addr,
 1198                                       unp->unp_addr->sun_len);
 1199                         if (unp->unp_conn != NULL &&
 1200                             unp->unp_conn->unp_addr != NULL)
 1201                                 bcopy(unp->unp_conn->unp_addr,
 1202                                       &xu->xu_caddr,
 1203                                       unp->unp_conn->unp_addr->sun_len);
 1204                         bcopy(unp, &xu->xu_unp, sizeof *unp);
 1205                         sotoxsocket(unp->unp_socket, &xu->xu_socket);
 1206                         error = SYSCTL_OUT(req, xu, sizeof *xu);
 1207                 }
 1208         }
 1209         free(xu, M_TEMP);
 1210         if (!error) {
 1211                 /*
 1212                  * Give the user an updated idea of our state.
 1213                  * If the generation differs from what we told
 1214                  * her before, she knows that something happened
 1215                  * while we were processing this request, and it
 1216                  * might be necessary to retry.
 1217                  */
 1218                 xug->xug_gen = unp_gencnt;
 1219                 xug->xug_sogen = so_gencnt;
 1220                 xug->xug_count = unp_count;
 1221                 error = SYSCTL_OUT(req, xug, sizeof *xug);
 1222         }
 1223         free(unp_list, M_TEMP);
 1224         free(xug, M_TEMP);
 1225         return (error);
 1226 }
 1227 
 1228 SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD,
 1229             (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb",
 1230             "List of active local datagram sockets");
 1231 SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD,
 1232             (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
 1233             "List of active local stream sockets");
 1234 
 1235 static void
 1236 unp_shutdown(struct unpcb *unp)
 1237 {
 1238         struct socket *so;
 1239 
 1240         UNP_LOCK_ASSERT();
 1241 
 1242         if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
 1243             (so = unp->unp_conn->unp_socket))
 1244                 socantrcvmore(so);
 1245 }
 1246 
 1247 static void
 1248 unp_drop(struct unpcb *unp, int errno)
 1249 {
 1250         struct socket *so = unp->unp_socket;
 1251 
 1252         UNP_LOCK_ASSERT();
 1253 
 1254         so->so_error = errno;
 1255         unp_disconnect(unp);
 1256 }
 1257 
 1258 #ifdef notdef
 1259 void
 1260 unp_drain(void)
 1261 {
 1262 
 1263 }
 1264 #endif
 1265 
 1266 static void
 1267 unp_freerights(struct file **rp, int fdcount)
 1268 {
 1269         int i;
 1270         struct file *fp;
 1271 
 1272         for (i = 0; i < fdcount; i++) {
 1273                 fp = *rp;
 1274                 /*
 1275                  * zero the pointer before calling
 1276                  * unp_discard since it may end up
 1277                  * in unp_gc()..
 1278                  */
 1279                 *rp++ = 0;
 1280                 unp_discard(fp);
 1281         }
 1282 }
 1283 
 1284 int
 1285 unp_externalize(struct mbuf *control, struct mbuf **controlp)
 1286 {
 1287         struct thread *td = curthread;          /* XXX */
 1288         struct cmsghdr *cm = mtod(control, struct cmsghdr *);
 1289         int i;
 1290         int *fdp;
 1291         struct file **rp;
 1292         struct file *fp;
 1293         void *data;
 1294         socklen_t clen = control->m_len, datalen;
 1295         int error, newfds;
 1296         int f;
 1297         u_int newlen;
 1298 
 1299         UNP_UNLOCK_ASSERT();
 1300 
 1301         error = 0;
 1302         if (controlp != NULL) /* controlp == NULL => free control messages */
 1303                 *controlp = NULL;
 1304 
 1305         while (cm != NULL) {
 1306                 if (sizeof(*cm) > clen || cm->cmsg_len > clen) {
 1307                         error = EINVAL;
 1308                         break;
 1309                 }
 1310 
 1311                 data = CMSG_DATA(cm);
 1312                 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 1313 
 1314                 if (cm->cmsg_level == SOL_SOCKET
 1315                     && cm->cmsg_type == SCM_RIGHTS) {
 1316                         newfds = datalen / sizeof(struct file *);
 1317                         rp = data;
 1318 
 1319                         /* If we're not outputting the descriptors free them. */
 1320                         if (error || controlp == NULL) {
 1321                                 unp_freerights(rp, newfds);
 1322                                 goto next;
 1323                         }
 1324                         FILEDESC_LOCK(td->td_proc->p_fd);
 1325                         /* if the new FD's will not fit free them.  */
 1326                         if (!fdavail(td, newfds)) {
 1327                                 FILEDESC_UNLOCK(td->td_proc->p_fd);
 1328                                 error = EMSGSIZE;
 1329                                 unp_freerights(rp, newfds);
 1330                                 goto next;
 1331                         }
 1332                         /*
 1333                          * now change each pointer to an fd in the global
 1334                          * table to an integer that is the index to the
 1335                          * local fd table entry that we set up to point
 1336                          * to the global one we are transferring.
 1337                          */
 1338                         newlen = newfds * sizeof(int);
 1339                         *controlp = sbcreatecontrol(NULL, newlen,
 1340                             SCM_RIGHTS, SOL_SOCKET);
 1341                         if (*controlp == NULL) {
 1342                                 FILEDESC_UNLOCK(td->td_proc->p_fd);
 1343                                 error = E2BIG;
 1344                                 unp_freerights(rp, newfds);
 1345                                 goto next;
 1346                         }
 1347 
 1348                         fdp = (int *)
 1349                             CMSG_DATA(mtod(*controlp, struct cmsghdr *));
 1350                         for (i = 0; i < newfds; i++) {
 1351                                 if (fdalloc(td, 0, &f))
 1352                                         panic("unp_externalize fdalloc failed");
 1353                                 fp = *rp++;
 1354                                 td->td_proc->p_fd->fd_ofiles[f] = fp;
 1355                                 FILE_LOCK(fp);
 1356                                 fp->f_msgcount--;
 1357                                 FILE_UNLOCK(fp);
 1358                                 unp_rights--;
 1359                                 *fdp++ = f;
 1360                         }
 1361                         FILEDESC_UNLOCK(td->td_proc->p_fd);
 1362                 } else { /* We can just copy anything else across */
 1363                         if (error || controlp == NULL)
 1364                                 goto next;
 1365                         *controlp = sbcreatecontrol(NULL, datalen,
 1366                             cm->cmsg_type, cm->cmsg_level);
 1367                         if (*controlp == NULL) {
 1368                                 error = ENOBUFS;
 1369                                 goto next;
 1370                         }
 1371                         bcopy(data,
 1372                             CMSG_DATA(mtod(*controlp, struct cmsghdr *)),
 1373                             datalen);
 1374                 }
 1375 
 1376                 controlp = &(*controlp)->m_next;
 1377 
 1378 next:
 1379                 if (CMSG_SPACE(datalen) < clen) {
 1380                         clen -= CMSG_SPACE(datalen);
 1381                         cm = (struct cmsghdr *)
 1382                             ((caddr_t)cm + CMSG_SPACE(datalen));
 1383                 } else {
 1384                         clen = 0;
 1385                         cm = NULL;
 1386                 }
 1387         }
 1388 
 1389         m_freem(control);
 1390 
 1391         return (error);
 1392 }
 1393 
 1394 static void
 1395 unp_zone_change(void *tag)
 1396 {
 1397 
 1398         uma_zone_set_max(unp_zone, maxsockets);
 1399 }
 1400 
 1401 void
 1402 unp_init(void)
 1403 {
 1404         unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, NULL,
 1405             NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 1406         if (unp_zone == NULL)
 1407                 panic("unp_init");
 1408         uma_zone_set_max(unp_zone, maxsockets);
 1409         EVENTHANDLER_REGISTER(maxsockets_change, unp_zone_change,
 1410             NULL, EVENTHANDLER_PRI_ANY);
 1411         LIST_INIT(&unp_dhead);
 1412         LIST_INIT(&unp_shead);
 1413         TASK_INIT(&unp_gc_task, 0, unp_gc, NULL);
 1414         UNP_LOCK_INIT();
 1415 }
 1416 
 1417 static int
 1418 unp_internalize(struct mbuf **controlp, struct thread *td)
 1419 {
 1420         struct mbuf *control = *controlp;
 1421         struct proc *p = td->td_proc;
 1422         struct filedesc *fdescp = p->p_fd;
 1423         struct cmsghdr *cm = mtod(control, struct cmsghdr *);
 1424         struct cmsgcred *cmcred;
 1425         struct file **rp;
 1426         struct file *fp;
 1427         struct timeval *tv;
 1428         int i, fd, *fdp;
 1429         void *data;
 1430         socklen_t clen = control->m_len, datalen;
 1431         int error, oldfds;
 1432         u_int newlen;
 1433 
 1434         UNP_UNLOCK_ASSERT();
 1435 
 1436         error = 0;
 1437         *controlp = NULL;
 1438 
 1439         while (cm != NULL) {
 1440                 if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
 1441                     || cm->cmsg_len > clen) {
 1442                         error = EINVAL;
 1443                         goto out;
 1444                 }
 1445 
 1446                 data = CMSG_DATA(cm);
 1447                 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
 1448 
 1449                 switch (cm->cmsg_type) {
 1450                 /*
 1451                  * Fill in credential information.
 1452                  */
 1453                 case SCM_CREDS:
 1454                         *controlp = sbcreatecontrol(NULL, sizeof(*cmcred),
 1455                             SCM_CREDS, SOL_SOCKET);
 1456                         if (*controlp == NULL) {
 1457                                 error = ENOBUFS;
 1458                                 goto out;
 1459                         }
 1460 
 1461                         cmcred = (struct cmsgcred *)
 1462                             CMSG_DATA(mtod(*controlp, struct cmsghdr *));
 1463                         cmcred->cmcred_pid = p->p_pid;
 1464                         cmcred->cmcred_uid = td->td_ucred->cr_ruid;
 1465                         cmcred->cmcred_gid = td->td_ucred->cr_rgid;
 1466                         cmcred->cmcred_euid = td->td_ucred->cr_uid;
 1467                         cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups,
 1468                                                         CMGROUP_MAX);
 1469                         for (i = 0; i < cmcred->cmcred_ngroups; i++)
 1470                                 cmcred->cmcred_groups[i] =
 1471                                     td->td_ucred->cr_groups[i];
 1472                         break;
 1473 
 1474                 case SCM_RIGHTS:
 1475                         oldfds = datalen / sizeof (int);
 1476                         /*
 1477                          * check that all the FDs passed in refer to legal files
 1478                          * If not, reject the entire operation.
 1479                          */
 1480                         fdp = data;
 1481                         FILEDESC_LOCK(fdescp);
 1482                         for (i = 0; i < oldfds; i++) {
 1483                                 fd = *fdp++;
 1484                                 if ((unsigned)fd >= fdescp->fd_nfiles ||
 1485                                     fdescp->fd_ofiles[fd] == NULL) {
 1486                                         FILEDESC_UNLOCK(fdescp);
 1487                                         error = EBADF;
 1488                                         goto out;
 1489                                 }
 1490                                 fp = fdescp->fd_ofiles[fd];
 1491                                 if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) {
 1492                                         FILEDESC_UNLOCK(fdescp);
 1493                                         error = EOPNOTSUPP;
 1494                                         goto out;
 1495                                 }
 1496 
 1497                         }
 1498                         /*
 1499                          * Now replace the integer FDs with pointers to
 1500                          * the associated global file table entry..
 1501                          */
 1502                         newlen = oldfds * sizeof(struct file *);
 1503                         *controlp = sbcreatecontrol(NULL, newlen,
 1504                             SCM_RIGHTS, SOL_SOCKET);
 1505                         if (*controlp == NULL) {
 1506                                 FILEDESC_UNLOCK(fdescp);
 1507                                 error = E2BIG;
 1508                                 goto out;
 1509                         }
 1510 
 1511                         fdp = data;
 1512                         rp = (struct file **)
 1513                             CMSG_DATA(mtod(*controlp, struct cmsghdr *));
 1514                         for (i = 0; i < oldfds; i++) {
 1515                                 fp = fdescp->fd_ofiles[*fdp++];
 1516                                 *rp++ = fp;
 1517                                 FILE_LOCK(fp);
 1518                                 fp->f_count++;
 1519                                 fp->f_msgcount++;
 1520                                 FILE_UNLOCK(fp);
 1521                                 unp_rights++;
 1522                         }
 1523                         FILEDESC_UNLOCK(fdescp);
 1524                         break;
 1525 
 1526                 case SCM_TIMESTAMP:
 1527                         *controlp = sbcreatecontrol(NULL, sizeof(*tv),
 1528                             SCM_TIMESTAMP, SOL_SOCKET);
 1529                         if (*controlp == NULL) {
 1530                                 error = ENOBUFS;
 1531                                 goto out;
 1532                         }
 1533                         tv = (struct timeval *)
 1534                             CMSG_DATA(mtod(*controlp, struct cmsghdr *));
 1535                         microtime(tv);
 1536                         break;
 1537 
 1538                 default:
 1539                         error = EINVAL;
 1540                         goto out;
 1541                 }
 1542 
 1543                 controlp = &(*controlp)->m_next;
 1544 
 1545                 if (CMSG_SPACE(datalen) < clen) {
 1546                         clen -= CMSG_SPACE(datalen);
 1547                         cm = (struct cmsghdr *)
 1548                             ((caddr_t)cm + CMSG_SPACE(datalen));
 1549                 } else {
 1550                         clen = 0;
 1551                         cm = NULL;
 1552                 }
 1553         }
 1554 
 1555 out:
 1556         m_freem(control);
 1557 
 1558         return (error);
 1559 }
 1560 
 1561 struct mbuf *
 1562 unp_addsockcred(struct thread *td, struct mbuf *control)
 1563 {
 1564         struct mbuf *m, *n, *n_prev;
 1565         struct sockcred *sc;
 1566         const struct cmsghdr *cm;
 1567         int ngroups;
 1568         int i;
 1569 
 1570         ngroups = MIN(td->td_ucred->cr_ngroups, CMGROUP_MAX);
 1571 
 1572         m = sbcreatecontrol(NULL, SOCKCREDSIZE(ngroups), SCM_CREDS, SOL_SOCKET);
 1573         if (m == NULL)
 1574                 return (control);
 1575 
 1576         sc = (struct sockcred *) CMSG_DATA(mtod(m, struct cmsghdr *));
 1577         sc->sc_uid = td->td_ucred->cr_ruid;
 1578         sc->sc_euid = td->td_ucred->cr_uid;
 1579         sc->sc_gid = td->td_ucred->cr_rgid;
 1580         sc->sc_egid = td->td_ucred->cr_gid;
 1581         sc->sc_ngroups = ngroups;
 1582         for (i = 0; i < sc->sc_ngroups; i++)
 1583                 sc->sc_groups[i] = td->td_ucred->cr_groups[i];
 1584 
 1585         /*
 1586          * Unlink SCM_CREDS control messages (struct cmsgcred), since
 1587          * just created SCM_CREDS control message (struct sockcred) has
 1588          * another format.
 1589          */
 1590         if (control != NULL)
 1591                 for (n = control, n_prev = NULL; n != NULL;) {
 1592                         cm = mtod(n, struct cmsghdr *);
 1593                         if (cm->cmsg_level == SOL_SOCKET &&
 1594                             cm->cmsg_type == SCM_CREDS) {
 1595                                 if (n_prev == NULL)
 1596                                         control = n->m_next;
 1597                                 else
 1598                                         n_prev->m_next = n->m_next;
 1599                                 n = m_free(n);
 1600                         } else {
 1601                                 n_prev = n;
 1602                                 n = n->m_next;
 1603                         }
 1604                 }
 1605 
 1606         /* Prepend it to the head. */
 1607         m->m_next = control;
 1608 
 1609         return (m);
 1610 }
 1611 
 1612 /*
 1613  * unp_defer indicates whether additional work has been defered for a future
 1614  * pass through unp_gc().  It is thread local and does not require explicit
 1615  * synchronization.
 1616  */
 1617 static int      unp_defer;
 1618 
 1619 static int unp_taskcount;
 1620 SYSCTL_INT(_net_local, OID_AUTO, taskcount, CTLFLAG_RD, &unp_taskcount, 0, "");
 1621 
 1622 static int unp_recycled;
 1623 SYSCTL_INT(_net_local, OID_AUTO, recycled, CTLFLAG_RD, &unp_recycled, 0, "");
 1624 
 1625 static void
 1626 unp_gc(__unused void *arg, int pending)
 1627 {
 1628         struct file *fp, *nextfp;
 1629         struct socket *so;
 1630         struct file **extra_ref, **fpp;
 1631         int nunref, i;
 1632         int nfiles_snap;
 1633         int nfiles_slack = 20;
 1634 
 1635         unp_taskcount++;
 1636         unp_defer = 0;
 1637         /*
 1638          * before going through all this, set all FDs to
 1639          * be NOT defered and NOT externally accessible
 1640          */
 1641         sx_slock(&filelist_lock);
 1642         LIST_FOREACH(fp, &filehead, f_list)
 1643                 fp->f_gcflag &= ~(FMARK|FDEFER);
 1644         do {
 1645                 LIST_FOREACH(fp, &filehead, f_list) {
 1646                         FILE_LOCK(fp);
 1647                         /*
 1648                          * If the file is not open, skip it -- could be a
 1649                          * file in the process of being opened, or in the
 1650                          * process of being closed.  If the file is
 1651                          * "closing", it may have been marked for deferred
 1652                          * consideration.  Clear the flag now if so.
 1653                          */
 1654                         if (fp->f_count == 0) {
 1655                                 if (fp->f_gcflag & FDEFER)
 1656                                         unp_defer--;
 1657                                 fp->f_gcflag &= ~(FMARK|FDEFER);
 1658                                 FILE_UNLOCK(fp);
 1659                                 continue;
 1660                         }
 1661                         /*
 1662                          * If we already marked it as 'defer'  in a
 1663                          * previous pass, then try process it this time
 1664                          * and un-mark it
 1665                          */
 1666                         if (fp->f_gcflag & FDEFER) {
 1667                                 fp->f_gcflag &= ~FDEFER;
 1668                                 unp_defer--;
 1669                         } else {
 1670                                 /*
 1671                                  * if it's not defered, then check if it's
 1672                                  * already marked.. if so skip it
 1673                                  */
 1674                                 if (fp->f_gcflag & FMARK) {
 1675                                         FILE_UNLOCK(fp);
 1676                                         continue;
 1677                                 }
 1678                                 /*
 1679                                  * If all references are from messages
 1680                                  * in transit, then skip it. it's not
 1681                                  * externally accessible.
 1682                                  */
 1683                                 if (fp->f_count == fp->f_msgcount) {
 1684                                         FILE_UNLOCK(fp);
 1685                                         continue;
 1686                                 }
 1687                                 /*
 1688                                  * If it got this far then it must be
 1689                                  * externally accessible.
 1690                                  */
 1691                                 fp->f_gcflag |= FMARK;
 1692                         }
 1693                         /*
 1694                          * either it was defered, or it is externally
 1695                          * accessible and not already marked so.
 1696                          * Now check if it is possibly one of OUR sockets.
 1697                          */
 1698                         if (fp->f_type != DTYPE_SOCKET ||
 1699                             (so = fp->f_data) == NULL) {
 1700                                 FILE_UNLOCK(fp);
 1701                                 continue;
 1702                         }
 1703                         FILE_UNLOCK(fp);
 1704                         if (so->so_proto->pr_domain != &localdomain ||
 1705                             (so->so_proto->pr_flags&PR_RIGHTS) == 0)
 1706                                 continue;
 1707                         /*
 1708                          * So, Ok, it's one of our sockets and it IS externally
 1709                          * accessible (or was defered). Now we look
 1710                          * to see if we hold any file descriptors in its
 1711                          * message buffers. Follow those links and mark them
 1712                          * as accessible too.
 1713                          */
 1714                         SOCKBUF_LOCK(&so->so_rcv);
 1715                         unp_scan(so->so_rcv.sb_mb, unp_mark);
 1716                         SOCKBUF_UNLOCK(&so->so_rcv);
 1717                 }
 1718         } while (unp_defer);
 1719         sx_sunlock(&filelist_lock);
 1720         /*
 1721          * XXXRW: The following comments need updating for a post-SMPng and
 1722          * deferred unp_gc() world, but are still generally accurate.
 1723          *
 1724          * We grab an extra reference to each of the file table entries
 1725          * that are not otherwise accessible and then free the rights
 1726          * that are stored in messages on them.
 1727          *
 1728          * The bug in the orginal code is a little tricky, so I'll describe
 1729          * what's wrong with it here.
 1730          *
 1731          * It is incorrect to simply unp_discard each entry for f_msgcount
 1732          * times -- consider the case of sockets A and B that contain
 1733          * references to each other.  On a last close of some other socket,
 1734          * we trigger a gc since the number of outstanding rights (unp_rights)
 1735          * is non-zero.  If during the sweep phase the gc code unp_discards,
 1736          * we end up doing a (full) closef on the descriptor.  A closef on A
 1737          * results in the following chain.  Closef calls soo_close, which
 1738          * calls soclose.   Soclose calls first (through the switch
 1739          * uipc_usrreq) unp_detach, which re-invokes unp_gc.  Unp_gc simply
 1740          * returns because the previous instance had set unp_gcing, and
 1741          * we return all the way back to soclose, which marks the socket
 1742          * with SS_NOFDREF, and then calls sofree.  Sofree calls sorflush
 1743          * to free up the rights that are queued in messages on the socket A,
 1744          * i.e., the reference on B.  The sorflush calls via the dom_dispose
 1745          * switch unp_dispose, which unp_scans with unp_discard.  This second
 1746          * instance of unp_discard just calls closef on B.
 1747          *
 1748          * Well, a similar chain occurs on B, resulting in a sorflush on B,
 1749          * which results in another closef on A.  Unfortunately, A is already
 1750          * being closed, and the descriptor has already been marked with
 1751          * SS_NOFDREF, and soclose panics at this point.
 1752          *
 1753          * Here, we first take an extra reference to each inaccessible
 1754          * descriptor.  Then, we call sorflush ourself, since we know
 1755          * it is a Unix domain socket anyhow.  After we destroy all the
 1756          * rights carried in messages, we do a last closef to get rid
 1757          * of our extra reference.  This is the last close, and the
 1758          * unp_detach etc will shut down the socket.
 1759          *
 1760          * 91/09/19, bsy@cs.cmu.edu
 1761          */
 1762 again:
 1763         nfiles_snap = openfiles + nfiles_slack; /* some slack */
 1764         extra_ref = malloc(nfiles_snap * sizeof(struct file *), M_TEMP,
 1765             M_WAITOK);
 1766         sx_slock(&filelist_lock);
 1767         if (nfiles_snap < openfiles) {
 1768                 sx_sunlock(&filelist_lock);
 1769                 free(extra_ref, M_TEMP);
 1770                 nfiles_slack += 20;
 1771                 goto again;
 1772         }
 1773         for (nunref = 0, fp = LIST_FIRST(&filehead), fpp = extra_ref;
 1774             fp != NULL; fp = nextfp) {
 1775                 nextfp = LIST_NEXT(fp, f_list);
 1776                 FILE_LOCK(fp);
 1777                 /*
 1778                  * If it's not open, skip it
 1779                  */
 1780                 if (fp->f_count == 0) {
 1781                         FILE_UNLOCK(fp);
 1782                         continue;
 1783                 }
 1784                 /*
 1785                  * If all refs are from msgs, and it's not marked accessible
 1786                  * then it must be referenced from some unreachable cycle
 1787                  * of (shut-down) FDs, so include it in our
 1788                  * list of FDs to remove
 1789                  */
 1790                 if (fp->f_count == fp->f_msgcount && !(fp->f_gcflag & FMARK)) {
 1791                         *fpp++ = fp;
 1792                         nunref++;
 1793                         fp->f_count++;
 1794                 }
 1795                 FILE_UNLOCK(fp);
 1796         }
 1797         sx_sunlock(&filelist_lock);
 1798         /*
 1799          * for each FD on our hit list, do the following two things
 1800          */
 1801         for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) {
 1802                 struct file *tfp = *fpp;
 1803                 FILE_LOCK(tfp);
 1804                 if (tfp->f_type == DTYPE_SOCKET &&
 1805                     tfp->f_data != NULL) {
 1806                         FILE_UNLOCK(tfp);
 1807                         sorflush(tfp->f_data);
 1808                 } else {
 1809                         FILE_UNLOCK(tfp);
 1810                 }
 1811         }
 1812         for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) {
 1813                 closef(*fpp, (struct thread *) NULL);
 1814                 unp_recycled++;
 1815         }
 1816         free(extra_ref, M_TEMP);
 1817 }
 1818 
 1819 void
 1820 unp_dispose(struct mbuf *m)
 1821 {
 1822 
 1823         if (m)
 1824                 unp_scan(m, unp_discard);
 1825 }
 1826 
 1827 static int
 1828 unp_listen(struct socket *so, struct unpcb *unp, struct thread *td)
 1829 {
 1830         int error;
 1831 
 1832         UNP_LOCK_ASSERT();
 1833 
 1834         SOCK_LOCK(so);
 1835         error = solisten_proto_check(so);
 1836         if (error == 0) {
 1837                 cru2x(td->td_ucred, &unp->unp_peercred);
 1838                 unp->unp_flags |= UNP_HAVEPCCACHED;
 1839                 solisten_proto(so);
 1840         }
 1841         SOCK_UNLOCK(so);
 1842         return (error);
 1843 }
 1844 
 1845 static void
 1846 unp_scan(struct mbuf *m0, void (*op)(struct file *))
 1847 {
 1848         struct mbuf *m;
 1849         struct file **rp;
 1850         struct cmsghdr *cm;
 1851         void *data;
 1852         int i;
 1853         socklen_t clen, datalen;
 1854         int qfds;
 1855 
 1856         while (m0 != NULL) {
 1857                 for (m = m0; m; m = m->m_next) {
 1858                         if (m->m_type != MT_CONTROL)
 1859                                 continue;
 1860 
 1861                         cm = mtod(m, struct cmsghdr *);
 1862                         clen = m->m_len;
 1863 
 1864                         while (cm != NULL) {
 1865                                 if (sizeof(*cm) > clen || cm->cmsg_len > clen)
 1866                                         break;
 1867 
 1868                                 data = CMSG_DATA(cm);
 1869                                 datalen = (caddr_t)cm + cm->cmsg_len
 1870                                     - (caddr_t)data;
 1871 
 1872                                 if (cm->cmsg_level == SOL_SOCKET &&
 1873                                     cm->cmsg_type == SCM_RIGHTS) {
 1874                                         qfds = datalen / sizeof (struct file *);
 1875                                         rp = data;
 1876                                         for (i = 0; i < qfds; i++)
 1877                                                 (*op)(*rp++);
 1878                                 }
 1879 
 1880                                 if (CMSG_SPACE(datalen) < clen) {
 1881                                         clen -= CMSG_SPACE(datalen);
 1882                                         cm = (struct cmsghdr *)
 1883                                             ((caddr_t)cm + CMSG_SPACE(datalen));
 1884                                 } else {
 1885                                         clen = 0;
 1886                                         cm = NULL;
 1887                                 }
 1888                         }
 1889                 }
 1890                 m0 = m0->m_act;
 1891         }
 1892 }
 1893 
 1894 static void
 1895 unp_mark(struct file *fp)
 1896 {
 1897         if (fp->f_gcflag & FMARK)
 1898                 return;
 1899         unp_defer++;
 1900         fp->f_gcflag |= (FMARK|FDEFER);
 1901 }
 1902 
 1903 static void
 1904 unp_discard(struct file *fp)
 1905 {
 1906         UNP_LOCK();
 1907         FILE_LOCK(fp);
 1908         fp->f_msgcount--;
 1909         unp_rights--;
 1910         FILE_UNLOCK(fp);
 1911         UNP_UNLOCK();
 1912         (void) closef(fp, (struct thread *)NULL);
 1913 }

Cache object: 9119daa1bd96110191579f8c194f0d72


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.