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