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