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