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

Cache object: 6a31add6be068422731eb336fba1c99b


[ 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.