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