Home | History | Annotate | Line # | Download | only in kern
uipc_usrreq.c revision 1.6
      1 /*
      2  * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
      3  * 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	7.26 (Berkeley) 6/3/91
     34  *	$Id: uipc_usrreq.c,v 1.6 1993/09/14 03:35:08 mycroft Exp $
     35  */
     36 
     37 #include "param.h"
     38 #include "proc.h"
     39 #include "filedesc.h"
     40 #include "domain.h"
     41 #include "protosw.h"
     42 #include "socket.h"
     43 #include "socketvar.h"
     44 #include "unpcb.h"
     45 #include "un.h"
     46 #include "namei.h"
     47 #include "vnode.h"
     48 #include "file.h"
     49 #include "stat.h"
     50 #include "mbuf.h"
     51 
     52 void unp_scan __P((struct mbuf *m0, void (*op) __P((struct file *))));
     53 void unp_shutdown __P((struct unpcb *unp));
     54 void unp_drop __P((struct unpcb *unp, int errno));
     55 void unp_gc __P((void));
     56 
     57 /*
     58  * Unix communications domain.
     59  *
     60  * TODO:
     61  *	SEQPACKET, RDM
     62  *	rethink name space problems
     63  *	need a proper out-of-band
     64  */
     65 struct	sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
     66 ino_t	unp_ino;			/* prototype for fake inode numbers */
     67 
     68 /*ARGSUSED*/
     69 int
     70 uipc_usrreq(so, req, m, nam, control)
     71 	struct socket *so;
     72 	int req;
     73 	struct mbuf *m, *nam, *control;
     74 {
     75 	struct unpcb *unp = sotounpcb(so);
     76 	register struct socket *so2;
     77 	register int error = 0;
     78 	struct proc *p = curproc;	/* XXX */
     79 
     80 	if (req == PRU_CONTROL)
     81 		return (EOPNOTSUPP);
     82 	if (req != PRU_SEND && control && control->m_len) {
     83 		error = EOPNOTSUPP;
     84 		goto release;
     85 	}
     86 	if (unp == 0 && req != PRU_ATTACH) {
     87 		error = EINVAL;
     88 		goto release;
     89 	}
     90 	switch (req) {
     91 
     92 	case PRU_ATTACH:
     93 		if (unp) {
     94 			error = EISCONN;
     95 			break;
     96 		}
     97 		error = unp_attach(so);
     98 		break;
     99 
    100 	case PRU_DETACH:
    101 		unp_detach(unp);
    102 		break;
    103 
    104 	case PRU_BIND:
    105 		error = unp_bind(unp, nam, p);
    106 		break;
    107 
    108 	case PRU_LISTEN:
    109 		if (unp->unp_vnode == 0)
    110 			error = EINVAL;
    111 		break;
    112 
    113 	case PRU_CONNECT:
    114 		error = unp_connect(so, nam, p);
    115 		break;
    116 
    117 	case PRU_CONNECT2:
    118 		error = unp_connect2(so, (struct socket *)nam);
    119 		break;
    120 
    121 	case PRU_DISCONNECT:
    122 		unp_disconnect(unp);
    123 		break;
    124 
    125 	case PRU_ACCEPT:
    126 		/*
    127 		 * Pass back name of connected socket,
    128 		 * if it was bound and we are still connected
    129 		 * (our peer may have closed already!).
    130 		 */
    131 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
    132 			nam->m_len = unp->unp_conn->unp_addr->m_len;
    133 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
    134 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
    135 		} else {
    136 			nam->m_len = sizeof(sun_noname);
    137 			*(mtod(nam, struct sockaddr *)) = sun_noname;
    138 		}
    139 		break;
    140 
    141 	case PRU_SHUTDOWN:
    142 		socantsendmore(so);
    143 		unp_shutdown(unp);
    144 		break;
    145 
    146 	case PRU_RCVD:
    147 		switch (so->so_type) {
    148 
    149 		case SOCK_DGRAM:
    150 			panic("uipc 1");
    151 			/*NOTREACHED*/
    152 
    153 		case SOCK_STREAM:
    154 #define	rcv (&so->so_rcv)
    155 #define snd (&so2->so_snd)
    156 			if (unp->unp_conn == 0)
    157 				break;
    158 			so2 = unp->unp_conn->unp_socket;
    159 			/*
    160 			 * Adjust backpressure on sender
    161 			 * and wakeup any waiting to write.
    162 			 */
    163 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
    164 			unp->unp_mbcnt = rcv->sb_mbcnt;
    165 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
    166 			unp->unp_cc = rcv->sb_cc;
    167 			sowwakeup(so2);
    168 #undef snd
    169 #undef rcv
    170 			break;
    171 
    172 		default:
    173 			panic("uipc 2");
    174 		}
    175 		break;
    176 
    177 	case PRU_SEND:
    178 		if (control && (error = unp_internalize(control, p)))
    179 			break;
    180 		switch (so->so_type) {
    181 
    182 		case SOCK_DGRAM: {
    183 			struct sockaddr *from;
    184 
    185 			if (nam) {
    186 				if (unp->unp_conn) {
    187 					error = EISCONN;
    188 					break;
    189 				}
    190 				error = unp_connect(so, nam, p);
    191 				if (error)
    192 					break;
    193 			} else {
    194 				if (unp->unp_conn == 0) {
    195 					error = ENOTCONN;
    196 					break;
    197 				}
    198 			}
    199 			so2 = unp->unp_conn->unp_socket;
    200 			if (unp->unp_addr)
    201 				from = mtod(unp->unp_addr, struct sockaddr *);
    202 			else
    203 				from = &sun_noname;
    204 			if (sbappendaddr(&so2->so_rcv, from, m, control)) {
    205 				sorwakeup(so2);
    206 				m = 0;
    207 				control = 0;
    208 			} else
    209 				error = ENOBUFS;
    210 			if (nam)
    211 				unp_disconnect(unp);
    212 			break;
    213 		}
    214 
    215 		case SOCK_STREAM:
    216 #define	rcv (&so2->so_rcv)
    217 #define	snd (&so->so_snd)
    218 			if (so->so_state & SS_CANTSENDMORE) {
    219 				error = EPIPE;
    220 				break;
    221 			}
    222 			if (unp->unp_conn == 0)
    223 				panic("uipc 3");
    224 			so2 = unp->unp_conn->unp_socket;
    225 			/*
    226 			 * Send to paired receive port, and then reduce
    227 			 * send buffer hiwater marks to maintain backpressure.
    228 			 * Wake up readers.
    229 			 */
    230 			if (control) {
    231 				if (sbappendcontrol(rcv, m, control))
    232 					control = 0;
    233 			} else
    234 				sbappend(rcv, m);
    235 			snd->sb_mbmax -=
    236 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
    237 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
    238 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
    239 			unp->unp_conn->unp_cc = rcv->sb_cc;
    240 			sorwakeup(so2);
    241 			m = 0;
    242 #undef snd
    243 #undef rcv
    244 			break;
    245 
    246 		default:
    247 			panic("uipc 4");
    248 		}
    249 		break;
    250 
    251 	case PRU_ABORT:
    252 		unp_drop(unp, ECONNABORTED);
    253 		break;
    254 
    255 	case PRU_SENSE:
    256 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
    257 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
    258 			so2 = unp->unp_conn->unp_socket;
    259 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
    260 		}
    261 		((struct stat *) m)->st_dev = NODEV;
    262 		if (unp->unp_ino == 0)
    263 			unp->unp_ino = unp_ino++;
    264 		((struct stat *) m)->st_ino = unp->unp_ino;
    265 		return (0);
    266 
    267 	case PRU_RCVOOB:
    268 		return (EOPNOTSUPP);
    269 
    270 	case PRU_SENDOOB:
    271 		error = EOPNOTSUPP;
    272 		break;
    273 
    274 	case PRU_SOCKADDR:
    275 		if (unp->unp_addr) {
    276 			nam->m_len = unp->unp_addr->m_len;
    277 			bcopy(mtod(unp->unp_addr, caddr_t),
    278 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
    279 		} else
    280 			nam->m_len = 0;
    281 		break;
    282 
    283 	case PRU_PEERADDR:
    284 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
    285 			nam->m_len = unp->unp_conn->unp_addr->m_len;
    286 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
    287 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
    288 		} else
    289 			nam->m_len = 0;
    290 		break;
    291 
    292 	case PRU_SLOWTIMO:
    293 		break;
    294 
    295 	default:
    296 		panic("piusrreq");
    297 	}
    298 release:
    299 	if (control)
    300 		m_freem(control);
    301 	if (m)
    302 		m_freem(m);
    303 	return (error);
    304 }
    305 
    306 /*
    307  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
    308  * for stream sockets, although the total for sender and receiver is
    309  * actually only PIPSIZ.
    310  * Datagram sockets really use the sendspace as the maximum datagram size,
    311  * and don't really want to reserve the sendspace.  Their recvspace should
    312  * be large enough for at least one max-size datagram plus address.
    313  */
    314 #define	PIPSIZ	4096
    315 u_long	unpst_sendspace = PIPSIZ;
    316 u_long	unpst_recvspace = PIPSIZ;
    317 u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
    318 u_long	unpdg_recvspace = 4*1024;
    319 
    320 int	unp_rights;			/* file descriptors in flight */
    321 
    322 int
    323 unp_attach(so)
    324 	struct socket *so;
    325 {
    326 	register struct mbuf *m;
    327 	register struct unpcb *unp;
    328 	int error;
    329 
    330 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
    331 		switch (so->so_type) {
    332 
    333 		case SOCK_STREAM:
    334 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
    335 			break;
    336 
    337 		case SOCK_DGRAM:
    338 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
    339 			break;
    340 		}
    341 		if (error)
    342 			return (error);
    343 	}
    344 	m = m_getclr(M_DONTWAIT, MT_PCB);
    345 	if (m == NULL)
    346 		return (ENOBUFS);
    347 	unp = mtod(m, struct unpcb *);
    348 	so->so_pcb = (caddr_t)unp;
    349 	unp->unp_socket = so;
    350 	return (0);
    351 }
    352 
    353 int
    354 unp_detach(unp)
    355 	register struct unpcb *unp;
    356 {
    357 
    358 	if (unp->unp_vnode) {
    359 		unp->unp_vnode->v_socket = 0;
    360 		vrele(unp->unp_vnode);
    361 		unp->unp_vnode = 0;
    362 	}
    363 	if (unp->unp_conn)
    364 		unp_disconnect(unp);
    365 	while (unp->unp_refs)
    366 		unp_drop(unp->unp_refs, ECONNRESET);
    367 	soisdisconnected(unp->unp_socket);
    368 	unp->unp_socket->so_pcb = 0;
    369 	m_freem(unp->unp_addr);
    370 	(void) m_free(dtom(unp));
    371 	if (unp_rights)
    372 		unp_gc();
    373 }
    374 
    375 int
    376 unp_bind(unp, nam, p)
    377 	struct unpcb *unp;
    378 	struct mbuf *nam;
    379 	struct proc *p;
    380 {
    381 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
    382 	register struct vnode *vp;
    383 	register struct nameidata *ndp;
    384 	struct vattr vattr;
    385 	int error;
    386 	struct nameidata nd;
    387 
    388 	ndp = &nd;
    389 	ndp->ni_dirp = soun->sun_path;
    390 	if (unp->unp_vnode != NULL)
    391 		return (EINVAL);
    392 	if (nam->m_len == MLEN) {
    393 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
    394 			return (EINVAL);
    395 	} else
    396 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
    397 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
    398 	ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
    399 	ndp->ni_segflg = UIO_SYSSPACE;
    400 	if (error = namei(ndp, p))
    401 		return (error);
    402 	vp = ndp->ni_vp;
    403 	if (vp != NULL) {
    404 		VOP_ABORTOP(ndp);
    405 		if (ndp->ni_dvp == vp)
    406 			vrele(ndp->ni_dvp);
    407 		else
    408 			vput(ndp->ni_dvp);
    409 		vrele(vp);
    410 		return (EADDRINUSE);
    411 	}
    412 	VATTR_NULL(&vattr);
    413 	vattr.va_type = VSOCK;
    414 	vattr.va_mode = 0777;
    415 	if (error = VOP_CREATE(ndp, &vattr, p))
    416 		return (error);
    417 	vp = ndp->ni_vp;
    418 	vp->v_socket = unp->unp_socket;
    419 	unp->unp_vnode = vp;
    420 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
    421 	VOP_UNLOCK(vp);
    422 	return (0);
    423 }
    424 
    425 int
    426 unp_connect(so, nam, p)
    427 	struct socket *so;
    428 	struct mbuf *nam;
    429 	struct proc *p;
    430 {
    431 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
    432 	register struct vnode *vp;
    433 	register struct socket *so2, *so3;
    434 	register struct nameidata *ndp;
    435 	struct unpcb *unp2, *unp3;
    436 	int error;
    437 	struct nameidata nd;
    438 
    439 	ndp = &nd;
    440 	ndp->ni_dirp = soun->sun_path;
    441 	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */
    442 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
    443 			return (EMSGSIZE);
    444 	} else
    445 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
    446 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
    447 	ndp->ni_segflg = UIO_SYSSPACE;
    448 	if (error = namei(ndp, p))
    449 		return (error);
    450 	vp = ndp->ni_vp;
    451 	if (vp->v_type != VSOCK) {
    452 		error = ENOTSOCK;
    453 		goto bad;
    454 	}
    455 	if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
    456 		goto bad;
    457 	so2 = vp->v_socket;
    458 	if (so2 == 0) {
    459 		error = ECONNREFUSED;
    460 		goto bad;
    461 	}
    462 	if (so->so_type != so2->so_type) {
    463 		error = EPROTOTYPE;
    464 		goto bad;
    465 	}
    466 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
    467 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
    468 		    (so3 = sonewconn(so2, 0)) == 0) {
    469 			error = ECONNREFUSED;
    470 			goto bad;
    471 		}
    472 		unp2 = sotounpcb(so2);
    473 		unp3 = sotounpcb(so3);
    474 		if (unp2->unp_addr)
    475 			unp3->unp_addr =
    476 				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
    477 		so2 = so3;
    478 	}
    479 	error = unp_connect2(so, so2);
    480 bad:
    481 	vput(vp);
    482 	return (error);
    483 }
    484 
    485 int
    486 unp_connect2(so, so2)
    487 	register struct socket *so;
    488 	register struct socket *so2;
    489 {
    490 	register struct unpcb *unp = sotounpcb(so);
    491 	register struct unpcb *unp2;
    492 
    493 	if (so2->so_type != so->so_type)
    494 		return (EPROTOTYPE);
    495 	unp2 = sotounpcb(so2);
    496 	unp->unp_conn = unp2;
    497 	switch (so->so_type) {
    498 
    499 	case SOCK_DGRAM:
    500 		unp->unp_nextref = unp2->unp_refs;
    501 		unp2->unp_refs = unp;
    502 		soisconnected(so);
    503 		break;
    504 
    505 	case SOCK_STREAM:
    506 		unp2->unp_conn = unp;
    507 		soisconnected(so);
    508 		soisconnected(so2);
    509 		break;
    510 
    511 	default:
    512 		panic("unp_connect2");
    513 	}
    514 	return (0);
    515 }
    516 
    517 void
    518 unp_disconnect(unp)
    519 	struct unpcb *unp;
    520 {
    521 	register struct unpcb *unp2 = unp->unp_conn;
    522 
    523 	if (unp2 == 0)
    524 		return;
    525 	unp->unp_conn = 0;
    526 	switch (unp->unp_socket->so_type) {
    527 
    528 	case SOCK_DGRAM:
    529 		if (unp2->unp_refs == unp)
    530 			unp2->unp_refs = unp->unp_nextref;
    531 		else {
    532 			unp2 = unp2->unp_refs;
    533 			for (;;) {
    534 				if (unp2 == 0)
    535 					panic("unp_disconnect");
    536 				if (unp2->unp_nextref == unp)
    537 					break;
    538 				unp2 = unp2->unp_nextref;
    539 			}
    540 			unp2->unp_nextref = unp->unp_nextref;
    541 		}
    542 		unp->unp_nextref = 0;
    543 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
    544 		break;
    545 
    546 	case SOCK_STREAM:
    547 		soisdisconnected(unp->unp_socket);
    548 		unp2->unp_conn = 0;
    549 		soisdisconnected(unp2->unp_socket);
    550 		break;
    551 	}
    552 }
    553 
    554 #ifdef notdef
    555 unp_abort(unp)
    556 	struct unpcb *unp;
    557 {
    558 
    559 	unp_detach(unp);
    560 }
    561 #endif
    562 
    563 void
    564 unp_shutdown(unp)
    565 	struct unpcb *unp;
    566 {
    567 	struct socket *so;
    568 
    569 	if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
    570 	    (so = unp->unp_conn->unp_socket))
    571 		socantrcvmore(so);
    572 }
    573 
    574 void
    575 unp_drop(unp, errno)
    576 	struct unpcb *unp;
    577 	int errno;
    578 {
    579 	struct socket *so = unp->unp_socket;
    580 
    581 	so->so_error = errno;
    582 	unp_disconnect(unp);
    583 	if (so->so_head) {
    584 		so->so_pcb = (caddr_t) 0;
    585 		m_freem(unp->unp_addr);
    586 		(void) m_free(dtom(unp));
    587 		sofree(so);
    588 	}
    589 }
    590 
    591 #ifdef notdef
    592 unp_drain()
    593 {
    594 
    595 }
    596 #endif
    597 
    598 int
    599 unp_externalize(rights)
    600 	struct mbuf *rights;
    601 {
    602 	struct proc *p = curproc;		/* XXX */
    603 	register int i;
    604 	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
    605 	register struct file **rp = (struct file **)(cm + 1);
    606 	register struct file *fp;
    607 	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
    608 	int f;
    609 
    610 	if (!fdavail(p, newfds)) {
    611 		for (i = 0; i < newfds; i++) {
    612 			fp = *rp;
    613 			unp_discard(fp);
    614 			*rp++ = 0;
    615 		}
    616 		return (EMSGSIZE);
    617 	}
    618 	for (i = 0; i < newfds; i++) {
    619 		if (fdalloc(p, 0, &f))
    620 			panic("unp_externalize");
    621 		fp = *rp;
    622 		p->p_fd->fd_ofiles[f] = fp;
    623 		fp->f_msgcount--;
    624 		unp_rights--;
    625 		*(int *)rp++ = f;
    626 	}
    627 	return (0);
    628 }
    629 
    630 int
    631 unp_internalize(control, p)
    632 	struct mbuf *control;
    633 	struct proc *p;
    634 {
    635 	struct filedesc *fdp = p->p_fd;
    636 	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
    637 	register struct file **rp;
    638 	register struct file *fp;
    639 	register int i, fd;
    640 	int oldfds;
    641 
    642 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
    643 	    cm->cmsg_len != control->m_len)
    644 		return (EINVAL);
    645 	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
    646 	rp = (struct file **)(cm + 1);
    647 	for (i = 0; i < oldfds; i++) {
    648 		fd = *(int *)rp++;
    649 		if ((unsigned)fd >= fdp->fd_nfiles ||
    650 		    fdp->fd_ofiles[fd] == NULL)
    651 			return (EBADF);
    652 	}
    653 	rp = (struct file **)(cm + 1);
    654 	for (i = 0; i < oldfds; i++) {
    655 		fp = fdp->fd_ofiles[*(int *)rp];
    656 		*rp++ = fp;
    657 		fp->f_count++;
    658 		fp->f_msgcount++;
    659 		unp_rights++;
    660 	}
    661 	return (0);
    662 }
    663 
    664 int	unp_defer, unp_gcing;
    665 extern	struct domain unixdomain;
    666 void unp_mark __P((struct file *fp));
    667 void unp_discard __P((struct file *fp));
    668 
    669 void
    670 unp_gc()
    671 {
    672 	register struct file *fp;
    673 	register struct socket *so;
    674 
    675 	if (unp_gcing)
    676 		return;
    677 	unp_gcing = 1;
    678 restart:
    679 	unp_defer = 0;
    680 	for (fp = filehead; fp; fp = fp->f_filef)
    681 		fp->f_flag &= ~(FMARK|FDEFER);
    682 	do {
    683 		for (fp = filehead; fp; fp = fp->f_filef) {
    684 			if (fp->f_count == 0)
    685 				continue;
    686 			if (fp->f_flag & FDEFER) {
    687 				fp->f_flag &= ~FDEFER;
    688 				unp_defer--;
    689 			} else {
    690 				if (fp->f_flag & FMARK)
    691 					continue;
    692 				if (fp->f_count == fp->f_msgcount)
    693 					continue;
    694 				fp->f_flag |= FMARK;
    695 			}
    696 			if (fp->f_type != DTYPE_SOCKET ||
    697 			    (so = (struct socket *)fp->f_data) == 0)
    698 				continue;
    699 			if (so->so_proto->pr_domain != &unixdomain ||
    700 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
    701 				continue;
    702 #ifdef notdef
    703 			if (so->so_rcv.sb_flags & SB_LOCK) {
    704 				/*
    705 				 * This is problematical; it's not clear
    706 				 * we need to wait for the sockbuf to be
    707 				 * unlocked (on a uniprocessor, at least),
    708 				 * and it's also not clear what to do
    709 				 * if sbwait returns an error due to receipt
    710 				 * of a signal.  If sbwait does return
    711 				 * an error, we'll go into an infinite
    712 				 * loop.  Delete all of this for now.
    713 				 */
    714 				(void) sbwait(&so->so_rcv);
    715 				goto restart;
    716 			}
    717 #endif
    718 			unp_scan(so->so_rcv.sb_mb, unp_mark);
    719 		}
    720 	} while (unp_defer);
    721 	for (fp = filehead; fp; fp = fp->f_filef) {
    722 		if (fp->f_count == 0)
    723 			continue;
    724 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
    725 			while (fp->f_msgcount)
    726 				unp_discard(fp);
    727 	}
    728 	unp_gcing = 0;
    729 }
    730 
    731 void
    732 unp_dispose(m)
    733 	struct mbuf *m;
    734 {
    735 	if (m)
    736 		unp_scan(m, unp_discard);
    737 }
    738 
    739 void
    740 unp_scan(m0, op)
    741 	register struct mbuf *m0;
    742 	void (*op) __P((struct file *));
    743 {
    744 	register struct mbuf *m;
    745 	register struct file **rp;
    746 	register struct cmsghdr *cm;
    747 	register int i;
    748 	int qfds;
    749 
    750 	while (m0) {
    751 		for (m = m0; m; m = m->m_next)
    752 			if (m->m_type == MT_CONTROL &&
    753 			    m->m_len >= sizeof(*cm)) {
    754 				cm = mtod(m, struct cmsghdr *);
    755 				if (cm->cmsg_level != SOL_SOCKET ||
    756 				    cm->cmsg_type != SCM_RIGHTS)
    757 					continue;
    758 				qfds = (cm->cmsg_len - sizeof *cm)
    759 						/ sizeof (struct file *);
    760 				rp = (struct file **)(cm + 1);
    761 				for (i = 0; i < qfds; i++)
    762 					(*op)(*rp++);
    763 				break;		/* XXX, but saves time */
    764 			}
    765 		m0 = m0->m_act;
    766 	}
    767 }
    768 
    769 void
    770 unp_mark(fp)
    771 	struct file *fp;
    772 {
    773 
    774 	if (fp->f_flag & FMARK)
    775 		return;
    776 	unp_defer++;
    777 	fp->f_flag |= (FMARK|FDEFER);
    778 }
    779 
    780 void
    781 unp_discard(fp)
    782 	struct file *fp;
    783 {
    784 	if (fp->f_msgcount == 0)
    785 		return;
    786 	fp->f_msgcount--;
    787 	unp_rights--;
    788 	(void) closef(fp, curproc);
    789 }
    790