uipc_usrreq.c revision 1.15 1 /* $NetBSD: uipc_usrreq.c,v 1.15 1995/08/17 02:57:20 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/filedesc.h>
42 #include <sys/domain.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/unpcb.h>
47 #include <sys/un.h>
48 #include <sys/namei.h>
49 #include <sys/vnode.h>
50 #include <sys/file.h>
51 #include <sys/stat.h>
52 #include <sys/mbuf.h>
53
54 /*
55 * Unix communications domain.
56 *
57 * TODO:
58 * SEQPACKET, RDM
59 * rethink name space problems
60 * need a proper out-of-band
61 */
62 struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
63 ino_t unp_ino; /* prototype for fake inode numbers */
64
65 /*ARGSUSED*/
66 int
67 uipc_usrreq(so, req, m, nam, control)
68 struct socket *so;
69 int req;
70 struct mbuf *m, *nam, *control;
71 {
72 struct unpcb *unp = sotounpcb(so);
73 register struct socket *so2;
74 register int error = 0;
75 struct proc *p = curproc; /* XXX */
76
77 if (req == PRU_CONTROL)
78 return (EOPNOTSUPP);
79 if (req != PRU_SEND && control && control->m_len) {
80 error = EOPNOTSUPP;
81 goto release;
82 }
83 if (unp == 0 && req != PRU_ATTACH) {
84 error = EINVAL;
85 goto release;
86 }
87 switch (req) {
88
89 case PRU_ATTACH:
90 if (unp) {
91 error = EISCONN;
92 break;
93 }
94 error = unp_attach(so);
95 break;
96
97 case PRU_DETACH:
98 unp_detach(unp);
99 break;
100
101 case PRU_BIND:
102 error = unp_bind(unp, nam, p);
103 break;
104
105 case PRU_LISTEN:
106 if (unp->unp_vnode == 0)
107 error = EINVAL;
108 break;
109
110 case PRU_CONNECT:
111 error = unp_connect(so, nam, p);
112 break;
113
114 case PRU_CONNECT2:
115 error = unp_connect2(so, (struct socket *)nam);
116 break;
117
118 case PRU_DISCONNECT:
119 unp_disconnect(unp);
120 break;
121
122 case PRU_ACCEPT:
123 /*
124 * Pass back name of connected socket,
125 * if it was bound and we are still connected
126 * (our peer may have closed already!).
127 */
128 if (unp->unp_conn && unp->unp_conn->unp_addr) {
129 nam->m_len = unp->unp_conn->unp_addr->m_len;
130 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
131 mtod(nam, caddr_t), (unsigned)nam->m_len);
132 } else {
133 nam->m_len = sizeof(sun_noname);
134 *(mtod(nam, struct sockaddr *)) = sun_noname;
135 }
136 break;
137
138 case PRU_SHUTDOWN:
139 socantsendmore(so);
140 unp_shutdown(unp);
141 break;
142
143 case PRU_RCVD:
144 switch (so->so_type) {
145
146 case SOCK_DGRAM:
147 panic("uipc 1");
148 /*NOTREACHED*/
149
150 case SOCK_STREAM:
151 #define rcv (&so->so_rcv)
152 #define snd (&so2->so_snd)
153 if (unp->unp_conn == 0)
154 break;
155 so2 = unp->unp_conn->unp_socket;
156 /*
157 * Adjust backpressure on sender
158 * and wakeup any waiting to write.
159 */
160 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
161 unp->unp_mbcnt = rcv->sb_mbcnt;
162 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
163 unp->unp_cc = rcv->sb_cc;
164 sowwakeup(so2);
165 #undef snd
166 #undef rcv
167 break;
168
169 default:
170 panic("uipc 2");
171 }
172 break;
173
174 case PRU_SEND:
175 if (control && (error = unp_internalize(control, p)))
176 break;
177 switch (so->so_type) {
178
179 case SOCK_DGRAM: {
180 struct sockaddr *from;
181
182 if (nam) {
183 if (unp->unp_conn) {
184 error = EISCONN;
185 break;
186 }
187 error = unp_connect(so, nam, p);
188 if (error)
189 break;
190 } else {
191 if (unp->unp_conn == 0) {
192 error = ENOTCONN;
193 break;
194 }
195 }
196 so2 = unp->unp_conn->unp_socket;
197 if (unp->unp_addr)
198 from = mtod(unp->unp_addr, struct sockaddr *);
199 else
200 from = &sun_noname;
201 if (sbappendaddr(&so2->so_rcv, from, m, control)) {
202 sorwakeup(so2);
203 m = 0;
204 control = 0;
205 } else
206 error = ENOBUFS;
207 if (nam)
208 unp_disconnect(unp);
209 break;
210 }
211
212 case SOCK_STREAM:
213 #define rcv (&so2->so_rcv)
214 #define snd (&so->so_snd)
215 if (so->so_state & SS_CANTSENDMORE) {
216 error = EPIPE;
217 break;
218 }
219 if (unp->unp_conn == 0)
220 panic("uipc 3");
221 so2 = unp->unp_conn->unp_socket;
222 /*
223 * Send to paired receive port, and then reduce
224 * send buffer hiwater marks to maintain backpressure.
225 * Wake up readers.
226 */
227 if (control) {
228 if (sbappendcontrol(rcv, m, control))
229 control = 0;
230 } else
231 sbappend(rcv, m);
232 snd->sb_mbmax -=
233 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
234 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
235 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
236 unp->unp_conn->unp_cc = rcv->sb_cc;
237 sorwakeup(so2);
238 m = 0;
239 #undef snd
240 #undef rcv
241 break;
242
243 default:
244 panic("uipc 4");
245 }
246 break;
247
248 case PRU_ABORT:
249 unp_drop(unp, ECONNABORTED);
250 break;
251
252 case PRU_SENSE:
253 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
254 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
255 so2 = unp->unp_conn->unp_socket;
256 ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
257 }
258 ((struct stat *) m)->st_dev = NODEV;
259 if (unp->unp_ino == 0)
260 unp->unp_ino = unp_ino++;
261 ((struct stat *) m)->st_ino = unp->unp_ino;
262 return (0);
263
264 case PRU_RCVOOB:
265 return (EOPNOTSUPP);
266
267 case PRU_SENDOOB:
268 error = EOPNOTSUPP;
269 break;
270
271 case PRU_SOCKADDR:
272 if (unp->unp_addr) {
273 nam->m_len = unp->unp_addr->m_len;
274 bcopy(mtod(unp->unp_addr, caddr_t),
275 mtod(nam, caddr_t), (unsigned)nam->m_len);
276 } else
277 nam->m_len = 0;
278 break;
279
280 case PRU_PEERADDR:
281 if (unp->unp_conn && unp->unp_conn->unp_addr) {
282 nam->m_len = unp->unp_conn->unp_addr->m_len;
283 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
284 mtod(nam, caddr_t), (unsigned)nam->m_len);
285 } else
286 nam->m_len = 0;
287 break;
288
289 case PRU_SLOWTIMO:
290 break;
291
292 default:
293 panic("piusrreq");
294 }
295 release:
296 if (control)
297 m_freem(control);
298 if (m)
299 m_freem(m);
300 return (error);
301 }
302
303 /*
304 * Both send and receive buffers are allocated PIPSIZ bytes of buffering
305 * for stream sockets, although the total for sender and receiver is
306 * actually only PIPSIZ.
307 * Datagram sockets really use the sendspace as the maximum datagram size,
308 * and don't really want to reserve the sendspace. Their recvspace should
309 * be large enough for at least one max-size datagram plus address.
310 */
311 #define PIPSIZ 4096
312 u_long unpst_sendspace = PIPSIZ;
313 u_long unpst_recvspace = PIPSIZ;
314 u_long unpdg_sendspace = 2*1024; /* really max datagram size */
315 u_long unpdg_recvspace = 4*1024;
316
317 int unp_rights; /* file descriptors in flight */
318
319 int
320 unp_attach(so)
321 struct socket *so;
322 {
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;
336
337 default:
338 panic("unp_attach");
339 }
340 if (error)
341 return (error);
342 }
343 unp = malloc(sizeof(*unp), M_PCB, M_NOWAIT);
344 if (unp == NULL)
345 return (ENOBUFS);
346 bzero((caddr_t)unp, sizeof(*unp));
347 unp->unp_socket = so;
348 so->so_pcb = unp;
349 return (0);
350 }
351
352 int
353 unp_detach(unp)
354 register struct unpcb *unp;
355 {
356
357 if (unp->unp_vnode) {
358 unp->unp_vnode->v_socket = 0;
359 vrele(unp->unp_vnode);
360 unp->unp_vnode = 0;
361 }
362 if (unp->unp_conn)
363 unp_disconnect(unp);
364 while (unp->unp_refs)
365 unp_drop(unp->unp_refs, ECONNRESET);
366 soisdisconnected(unp->unp_socket);
367 unp->unp_socket->so_pcb = 0;
368 m_freem(unp->unp_addr);
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);
378 free(unp, M_PCB);
379 unp_gc();
380 } else
381 free(unp, M_PCB);
382 }
383
384 int
385 unp_bind(unp, nam, p)
386 struct unpcb *unp;
387 struct mbuf *nam;
388 struct proc *p;
389 {
390 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
391 register struct vnode *vp;
392 struct vattr vattr;
393 int error;
394 struct nameidata nd;
395
396 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
397 soun->sun_path, p);
398 if (unp->unp_vnode != NULL)
399 return (EINVAL);
400 if (nam->m_len == MLEN) {
401 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
402 return (EINVAL);
403 } else
404 *(mtod(nam, caddr_t) + nam->m_len) = 0;
405 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
406 if (error = namei(&nd))
407 return (error);
408 vp = nd.ni_vp;
409 if (vp != NULL) {
410 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
411 if (nd.ni_dvp == vp)
412 vrele(nd.ni_dvp);
413 else
414 vput(nd.ni_dvp);
415 vrele(vp);
416 return (EADDRINUSE);
417 }
418 VATTR_NULL(&vattr);
419 vattr.va_type = VSOCK;
420 vattr.va_mode = ACCESSPERMS;
421 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
422 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
423 return (error);
424 vp = nd.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
432 int
433 unp_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 struct unpcb *unp2, *unp3;
442 int error;
443 struct nameidata nd;
444
445 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
446 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
447 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
448 return (EMSGSIZE);
449 } else
450 *(mtod(nam, caddr_t) + nam->m_len) = 0;
451 if (error = namei(&nd))
452 return (error);
453 vp = nd.ni_vp;
454 if (vp->v_type != VSOCK) {
455 error = ENOTSOCK;
456 goto bad;
457 }
458 if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
459 goto bad;
460 so2 = vp->v_socket;
461 if (so2 == 0) {
462 error = ECONNREFUSED;
463 goto bad;
464 }
465 if (so->so_type != so2->so_type) {
466 error = EPROTOTYPE;
467 goto bad;
468 }
469 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
470 if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
471 (so3 = sonewconn(so2, 0)) == 0) {
472 error = ECONNREFUSED;
473 goto bad;
474 }
475 unp2 = sotounpcb(so2);
476 unp3 = sotounpcb(so3);
477 if (unp2->unp_addr)
478 unp3->unp_addr =
479 m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
480 so2 = so3;
481 }
482 error = unp_connect2(so, so2);
483 bad:
484 vput(vp);
485 return (error);
486 }
487
488 int
489 unp_connect2(so, so2)
490 register struct socket *so;
491 register struct socket *so2;
492 {
493 register struct unpcb *unp = sotounpcb(so);
494 register struct unpcb *unp2;
495
496 if (so2->so_type != so->so_type)
497 return (EPROTOTYPE);
498 unp2 = sotounpcb(so2);
499 unp->unp_conn = unp2;
500 switch (so->so_type) {
501
502 case SOCK_DGRAM:
503 unp->unp_nextref = unp2->unp_refs;
504 unp2->unp_refs = unp;
505 soisconnected(so);
506 break;
507
508 case SOCK_STREAM:
509 unp2->unp_conn = unp;
510 soisconnected(so);
511 soisconnected(so2);
512 break;
513
514 default:
515 panic("unp_connect2");
516 }
517 return (0);
518 }
519
520 void
521 unp_disconnect(unp)
522 struct unpcb *unp;
523 {
524 register struct unpcb *unp2 = unp->unp_conn;
525
526 if (unp2 == 0)
527 return;
528 unp->unp_conn = 0;
529 switch (unp->unp_socket->so_type) {
530
531 case SOCK_DGRAM:
532 if (unp2->unp_refs == unp)
533 unp2->unp_refs = unp->unp_nextref;
534 else {
535 unp2 = unp2->unp_refs;
536 for (;;) {
537 if (unp2 == 0)
538 panic("unp_disconnect");
539 if (unp2->unp_nextref == unp)
540 break;
541 unp2 = unp2->unp_nextref;
542 }
543 unp2->unp_nextref = unp->unp_nextref;
544 }
545 unp->unp_nextref = 0;
546 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
547 break;
548
549 case SOCK_STREAM:
550 soisdisconnected(unp->unp_socket);
551 unp2->unp_conn = 0;
552 soisdisconnected(unp2->unp_socket);
553 break;
554 }
555 }
556
557 #ifdef notdef
558 unp_abort(unp)
559 struct unpcb *unp;
560 {
561
562 unp_detach(unp);
563 }
564 #endif
565
566 void
567 unp_shutdown(unp)
568 struct unpcb *unp;
569 {
570 struct socket *so;
571
572 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
573 (so = unp->unp_conn->unp_socket))
574 socantrcvmore(so);
575 }
576
577 void
578 unp_drop(unp, errno)
579 struct unpcb *unp;
580 int errno;
581 {
582 struct socket *so = unp->unp_socket;
583
584 so->so_error = errno;
585 unp_disconnect(unp);
586 if (so->so_head) {
587 so->so_pcb = 0;
588 sofree(so);
589 m_freem(unp->unp_addr);
590 free(unp, M_PCB);
591 }
592 }
593
594 #ifdef notdef
595 unp_drain()
596 {
597
598 }
599 #endif
600
601 int
602 unp_externalize(rights)
603 struct mbuf *rights;
604 {
605 struct proc *p = curproc; /* XXX */
606 register int i;
607 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
608 register struct file **rp = (struct file **)(cm + 1);
609 register struct file *fp;
610 int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
611 int f;
612
613 if (!fdavail(p, newfds)) {
614 for (i = 0; i < newfds; i++) {
615 fp = *rp;
616 unp_discard(fp);
617 *rp++ = 0;
618 }
619 return (EMSGSIZE);
620 }
621 for (i = 0; i < newfds; i++) {
622 if (fdalloc(p, 0, &f))
623 panic("unp_externalize");
624 fp = *rp;
625 p->p_fd->fd_ofiles[f] = fp;
626 fp->f_msgcount--;
627 unp_rights--;
628 *(int *)rp++ = f;
629 }
630 return (0);
631 }
632
633 int
634 unp_internalize(control, p)
635 struct mbuf *control;
636 struct proc *p;
637 {
638 struct filedesc *fdp = p->p_fd;
639 register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
640 register struct file **rp;
641 register struct file *fp;
642 register int i, fd;
643 int oldfds;
644
645 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
646 cm->cmsg_len != control->m_len)
647 return (EINVAL);
648 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
649 rp = (struct file **)(cm + 1);
650 for (i = 0; i < oldfds; i++) {
651 fd = *(int *)rp++;
652 if ((unsigned)fd >= fdp->fd_nfiles ||
653 fdp->fd_ofiles[fd] == NULL)
654 return (EBADF);
655 }
656 rp = (struct file **)(cm + 1);
657 for (i = 0; i < oldfds; i++) {
658 fp = fdp->fd_ofiles[*(int *)rp];
659 *rp++ = fp;
660 fp->f_count++;
661 fp->f_msgcount++;
662 unp_rights++;
663 }
664 return (0);
665 }
666
667 int unp_defer, unp_gcing;
668 extern struct domain unixdomain;
669
670 void
671 unp_gc()
672 {
673 register struct file *fp, *nextfp;
674 register struct socket *so;
675 struct file **extra_ref, **fpp;
676 int nunref, i;
677
678 if (unp_gcing)
679 return;
680 unp_gcing = 1;
681 unp_defer = 0;
682 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next)
683 fp->f_flag &= ~(FMARK|FDEFER);
684 do {
685 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
686 if (fp->f_count == 0)
687 continue;
688 if (fp->f_flag & FDEFER) {
689 fp->f_flag &= ~FDEFER;
690 unp_defer--;
691 } else {
692 if (fp->f_flag & FMARK)
693 continue;
694 if (fp->f_count == fp->f_msgcount)
695 continue;
696 fp->f_flag |= FMARK;
697 }
698 if (fp->f_type != DTYPE_SOCKET ||
699 (so = (struct socket *)fp->f_data) == 0)
700 continue;
701 if (so->so_proto->pr_domain != &unixdomain ||
702 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
703 continue;
704 #ifdef notdef
705 if (so->so_rcv.sb_flags & SB_LOCK) {
706 /*
707 * This is problematical; it's not clear
708 * we need to wait for the sockbuf to be
709 * unlocked (on a uniprocessor, at least),
710 * and it's also not clear what to do
711 * if sbwait returns an error due to receipt
712 * of a signal. If sbwait does return
713 * an error, we'll go into an infinite
714 * loop. Delete all of this for now.
715 */
716 (void) sbwait(&so->so_rcv);
717 goto restart;
718 }
719 #endif
720 unp_scan(so->so_rcv.sb_mb, unp_mark);
721 }
722 } while (unp_defer);
723 /*
724 * We grab an extra reference to each of the file table entries
725 * that are not otherwise accessible and then free the rights
726 * that are stored in messages on them.
727 *
728 * The bug in the orginal code is a little tricky, so I'll describe
729 * what's wrong with it here.
730 *
731 * It is incorrect to simply unp_discard each entry for f_msgcount
732 * times -- consider the case of sockets A and B that contain
733 * references to each other. On a last close of some other socket,
734 * we trigger a gc since the number of outstanding rights (unp_rights)
735 * is non-zero. If during the sweep phase the gc code un_discards,
736 * we end up doing a (full) closef on the descriptor. A closef on A
737 * results in the following chain. Closef calls soo_close, which
738 * calls soclose. Soclose calls first (through the switch
739 * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply
740 * returns because the previous instance had set unp_gcing, and
741 * we return all the way back to soclose, which marks the socket
742 * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush
743 * to free up the rights that are queued in messages on the socket A,
744 * i.e., the reference on B. The sorflush calls via the dom_dispose
745 * switch unp_dispose, which unp_scans with unp_discard. This second
746 * instance of unp_discard just calls closef on B.
747 *
748 * Well, a similar chain occurs on B, resulting in a sorflush on B,
749 * which results in another closef on A. Unfortunately, A is already
750 * being closed, and the descriptor has already been marked with
751 * SS_NOFDREF, and soclose panics at this point.
752 *
753 * Here, we first take an extra reference to each inaccessible
754 * descriptor. Then, we call sorflush ourself, since we know
755 * it is a Unix domain socket anyhow. After we destroy all the
756 * rights carried in messages, we do a last closef to get rid
757 * of our extra reference. This is the last close, and the
758 * unp_detach etc will shut down the socket.
759 *
760 * 91/09/19, bsy (at) cs.cmu.edu
761 */
762 extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
763 for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0;
764 fp = nextfp) {
765 nextfp = fp->f_list.le_next;
766 if (fp->f_count == 0)
767 continue;
768 if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
769 *fpp++ = fp;
770 nunref++;
771 fp->f_count++;
772 }
773 }
774 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
775 sorflush((struct socket *)(*fpp)->f_data);
776 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
777 (void) closef(*fpp, (struct proc *)0);
778 free((caddr_t)extra_ref, M_FILE);
779 unp_gcing = 0;
780 }
781
782 void
783 unp_dispose(m)
784 struct mbuf *m;
785 {
786
787 if (m)
788 unp_scan(m, unp_discard);
789 }
790
791 void
792 unp_scan(m0, op)
793 register struct mbuf *m0;
794 void (*op) __P((struct file *));
795 {
796 register struct mbuf *m;
797 register struct file **rp;
798 register struct cmsghdr *cm;
799 register int i;
800 int qfds;
801
802 while (m0) {
803 for (m = m0; m; m = m->m_next)
804 if (m->m_type == MT_CONTROL &&
805 m->m_len >= sizeof(*cm)) {
806 cm = mtod(m, struct cmsghdr *);
807 if (cm->cmsg_level != SOL_SOCKET ||
808 cm->cmsg_type != SCM_RIGHTS)
809 continue;
810 qfds = (cm->cmsg_len - sizeof *cm)
811 / sizeof (struct file *);
812 rp = (struct file **)(cm + 1);
813 for (i = 0; i < qfds; i++)
814 (*op)(*rp++);
815 break; /* XXX, but saves time */
816 }
817 m0 = m0->m_act;
818 }
819 }
820
821 void
822 unp_mark(fp)
823 struct file *fp;
824 {
825
826 if (fp->f_flag & FMARK)
827 return;
828 unp_defer++;
829 fp->f_flag |= (FMARK|FDEFER);
830 }
831
832 void
833 unp_discard(fp)
834 struct file *fp;
835 {
836
837 fp->f_msgcount--;
838 unp_rights--;
839 (void) closef(fp, (struct proc *)0);
840 }
841