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