This source file includes following definitions.
- uipc_usrreq
- unp_attach
- unp_detach
- unp_bind
- unp_connect
- unp_connect2
- unp_disconnect
- unp_abort
- unp_shutdown
- unp_drop
- unp_drain
- unp_externalize
- unp_internalize
- unp_gc
- unp_dispose
- unp_scan
- unp_mark
- unp_discard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/filedesc.h>
39 #include <sys/domain.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/unpcb.h>
44 #include <sys/un.h>
45 #include <sys/namei.h>
46 #include <sys/vnode.h>
47 #include <sys/file.h>
48 #include <sys/stat.h>
49 #include <sys/mbuf.h>
50
51
52
53
54
55
56
57
58
59 struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
60 ino_t unp_ino;
61
62
63 int
64 uipc_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
65 struct mbuf *control)
66 {
67 struct unpcb *unp = sotounpcb(so);
68 struct socket *so2;
69 int error = 0;
70 struct proc *p = curproc;
71
72 if (req == PRU_CONTROL)
73 return (EOPNOTSUPP);
74 if (req != PRU_SEND && control && control->m_len) {
75 error = EOPNOTSUPP;
76 goto release;
77 }
78 if (unp == NULL && req != PRU_ATTACH) {
79 error = EINVAL;
80 goto release;
81 }
82 switch (req) {
83
84 case PRU_ATTACH:
85 if (unp) {
86 error = EISCONN;
87 break;
88 }
89 error = unp_attach(so);
90 break;
91
92 case PRU_DETACH:
93 unp_detach(unp);
94 break;
95
96 case PRU_BIND:
97 error = unp_bind(unp, nam, p);
98 break;
99
100 case PRU_LISTEN:
101 if (unp->unp_vnode == NULL)
102 error = EINVAL;
103 break;
104
105 case PRU_CONNECT:
106 error = unp_connect(so, nam, p);
107 break;
108
109 case PRU_CONNECT2:
110 error = unp_connect2(so, (struct socket *)nam);
111 break;
112
113 case PRU_DISCONNECT:
114 unp_disconnect(unp);
115 break;
116
117 case PRU_ACCEPT:
118
119
120
121
122
123 if (unp->unp_conn && unp->unp_conn->unp_addr) {
124 nam->m_len = unp->unp_conn->unp_addr->m_len;
125 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
126 mtod(nam, caddr_t), (unsigned)nam->m_len);
127 } else {
128 nam->m_len = sizeof(sun_noname);
129 *(mtod(nam, struct sockaddr *)) = sun_noname;
130 }
131 break;
132
133 case PRU_SHUTDOWN:
134 socantsendmore(so);
135 unp_shutdown(unp);
136 break;
137
138 case PRU_RCVD:
139 switch (so->so_type) {
140
141 case SOCK_DGRAM:
142 panic("uipc 1");
143
144
145 case SOCK_STREAM:
146 #define rcv (&so->so_rcv)
147 #define snd (&so2->so_snd)
148 if (unp->unp_conn == NULL)
149 break;
150 so2 = unp->unp_conn->unp_socket;
151
152
153
154
155 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
156 unp->unp_mbcnt = rcv->sb_mbcnt;
157 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
158 unp->unp_cc = rcv->sb_cc;
159 sowwakeup(so2);
160 #undef snd
161 #undef rcv
162 break;
163
164 default:
165 panic("uipc 2");
166 }
167 break;
168
169 case PRU_SEND:
170 if (control && (error = unp_internalize(control, p)))
171 break;
172 switch (so->so_type) {
173
174 case SOCK_DGRAM: {
175 struct sockaddr *from;
176
177 if (nam) {
178 if (unp->unp_conn) {
179 error = EISCONN;
180 break;
181 }
182 error = unp_connect(so, nam, p);
183 if (error)
184 break;
185 } else {
186 if (unp->unp_conn == NULL) {
187 error = ENOTCONN;
188 break;
189 }
190 }
191 so2 = unp->unp_conn->unp_socket;
192 if (unp->unp_addr)
193 from = mtod(unp->unp_addr, struct sockaddr *);
194 else
195 from = &sun_noname;
196 if (sbappendaddr(&so2->so_rcv, from, m, control)) {
197 sorwakeup(so2);
198 m = NULL;
199 control = NULL;
200 } else
201 error = ENOBUFS;
202 if (nam)
203 unp_disconnect(unp);
204 break;
205 }
206
207 case SOCK_STREAM:
208 #define rcv (&so2->so_rcv)
209 #define snd (&so->so_snd)
210 if (so->so_state & SS_CANTSENDMORE) {
211 error = EPIPE;
212 break;
213 }
214 if (unp->unp_conn == NULL) {
215 error = ENOTCONN;
216 break;
217 }
218 so2 = unp->unp_conn->unp_socket;
219
220
221
222
223
224 if (control) {
225 if (sbappendcontrol(rcv, m, control))
226 control = NULL;
227 } else
228 sbappend(rcv, m);
229 snd->sb_mbmax -=
230 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
231 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
232 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
233 unp->unp_conn->unp_cc = rcv->sb_cc;
234 sorwakeup(so2);
235 m = NULL;
236 #undef snd
237 #undef rcv
238 break;
239
240 default:
241 panic("uipc 4");
242 }
243
244 if (control && error)
245 unp_dispose(control);
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 != NULL) {
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_atimespec =
262 ((struct stat *) m)->st_mtimespec =
263 ((struct stat *) m)->st_ctimespec = unp->unp_ctime;
264 ((struct stat *) m)->st_ino = unp->unp_ino;
265 return (0);
266
267 case PRU_RCVOOB:
268 return (EOPNOTSUPP);
269
270 case PRU_SENDOOB:
271 error = EOPNOTSUPP;
272 break;
273
274 case PRU_SOCKADDR:
275 if (unp->unp_addr) {
276 nam->m_len = unp->unp_addr->m_len;
277 bcopy(mtod(unp->unp_addr, caddr_t),
278 mtod(nam, caddr_t), (unsigned)nam->m_len);
279 } else
280 nam->m_len = 0;
281 break;
282
283 case PRU_PEERADDR:
284 if (unp->unp_conn && unp->unp_conn->unp_addr) {
285 nam->m_len = unp->unp_conn->unp_addr->m_len;
286 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
287 mtod(nam, caddr_t), (unsigned)nam->m_len);
288 } else
289 nam->m_len = 0;
290 break;
291
292 case PRU_PEEREID:
293 if (unp->unp_flags & UNP_FEIDS) {
294 nam->m_len = sizeof(struct unpcbid);
295 bcopy((caddr_t)(&(unp->unp_connid)),
296 mtod(nam, caddr_t), (unsigned)nam->m_len);
297 } else
298 nam->m_len = 0;
299 break;
300
301 case PRU_SLOWTIMO:
302 break;
303
304 default:
305 panic("piusrreq");
306 }
307 release:
308 if (control)
309 m_freem(control);
310 if (m)
311 m_freem(m);
312 return (error);
313 }
314
315
316
317
318
319
320
321
322
323 #define PIPSIZ 4096
324 u_long unpst_sendspace = PIPSIZ;
325 u_long unpst_recvspace = PIPSIZ;
326 u_long unpdg_sendspace = 2*1024;
327 u_long unpdg_recvspace = 4*1024;
328
329 int unp_rights;
330
331 int
332 unp_attach(struct socket *so)
333 {
334 struct unpcb *unp;
335 int error;
336
337 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
338 switch (so->so_type) {
339
340 case SOCK_STREAM:
341 error = soreserve(so, unpst_sendspace, unpst_recvspace);
342 break;
343
344 case SOCK_DGRAM:
345 error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
346 break;
347
348 default:
349 panic("unp_attach");
350 }
351 if (error)
352 return (error);
353 }
354 unp = malloc(sizeof(*unp), M_PCB, M_NOWAIT);
355 if (unp == NULL)
356 return (ENOBUFS);
357 bzero((caddr_t)unp, sizeof(*unp));
358 unp->unp_socket = so;
359 so->so_pcb = unp;
360 nanotime(&unp->unp_ctime);
361 return (0);
362 }
363
364 void
365 unp_detach(struct unpcb *unp)
366 {
367
368 if (unp->unp_vnode) {
369 unp->unp_vnode->v_socket = NULL;
370 vrele(unp->unp_vnode);
371 unp->unp_vnode = NULL;
372 }
373 if (unp->unp_conn)
374 unp_disconnect(unp);
375 while (unp->unp_refs)
376 unp_drop(unp->unp_refs, ECONNRESET);
377 soisdisconnected(unp->unp_socket);
378 unp->unp_socket->so_pcb = NULL;
379 m_freem(unp->unp_addr);
380 if (unp_rights) {
381
382
383
384
385
386
387
388 sorflush(unp->unp_socket);
389 free(unp, M_PCB);
390 unp_gc();
391 } else
392 free(unp, M_PCB);
393 }
394
395 int
396 unp_bind(struct unpcb *unp, struct mbuf *nam, struct proc *p)
397 {
398 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
399 struct vnode *vp;
400 struct vattr vattr;
401 int error, namelen;
402 struct nameidata nd;
403 char buf[MLEN];
404
405 if (unp->unp_vnode != NULL)
406 return (EINVAL);
407 namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
408 if (namelen <= 0 || namelen >= MLEN)
409 return EINVAL;
410 strncpy(buf, soun->sun_path, namelen);
411 buf[namelen] = 0;
412 NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE, buf, p);
413
414 if ((error = namei(&nd)) != 0)
415 return (error);
416 vp = nd.ni_vp;
417 if (vp != NULL) {
418 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
419 if (nd.ni_dvp == vp)
420 vrele(nd.ni_dvp);
421 else
422 vput(nd.ni_dvp);
423 vrele(vp);
424 return (EADDRINUSE);
425 }
426 VATTR_NULL(&vattr);
427 vattr.va_type = VSOCK;
428 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
429 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
430 if (error)
431 return (error);
432 vp = nd.ni_vp;
433 vp->v_socket = unp->unp_socket;
434 unp->unp_vnode = vp;
435 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
436 unp->unp_connid.unp_euid = p->p_ucred->cr_uid;
437 unp->unp_connid.unp_egid = p->p_ucred->cr_gid;
438 unp->unp_flags |= UNP_FEIDSBIND;
439 VOP_UNLOCK(vp, 0, p);
440 return (0);
441 }
442
443 int
444 unp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
445 {
446 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
447 struct vnode *vp;
448 struct socket *so2, *so3;
449 struct unpcb *unp, *unp2, *unp3;
450 int error;
451 struct nameidata nd;
452
453 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
454 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {
455 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
456 return (EMSGSIZE);
457 } else
458 *(mtod(nam, caddr_t) + nam->m_len) = 0;
459 if ((error = namei(&nd)) != 0)
460 return (error);
461 vp = nd.ni_vp;
462 if (vp->v_type != VSOCK) {
463 error = ENOTSOCK;
464 goto bad;
465 }
466 if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) != 0)
467 goto bad;
468 so2 = vp->v_socket;
469 if (so2 == NULL) {
470 error = ECONNREFUSED;
471 goto bad;
472 }
473 if (so->so_type != so2->so_type) {
474 error = EPROTOTYPE;
475 goto bad;
476 }
477 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
478 if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
479 (so3 = sonewconn(so2, 0)) == 0) {
480 error = ECONNREFUSED;
481 goto bad;
482 }
483 unp = sotounpcb(so);
484 unp2 = sotounpcb(so2);
485 unp3 = sotounpcb(so3);
486 if (unp2->unp_addr)
487 unp3->unp_addr =
488 m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
489 unp3->unp_connid.unp_euid = p->p_ucred->cr_uid;
490 unp3->unp_connid.unp_egid = p->p_ucred->cr_gid;
491 unp3->unp_flags |= UNP_FEIDS;
492 so2 = so3;
493 if (unp2->unp_flags & UNP_FEIDSBIND) {
494 unp->unp_connid.unp_euid = unp2->unp_connid.unp_euid;
495 unp->unp_connid.unp_egid = unp2->unp_connid.unp_egid;
496 unp->unp_flags |= UNP_FEIDS;
497 }
498 }
499 error = unp_connect2(so, so2);
500 bad:
501 vput(vp);
502 return (error);
503 }
504
505 int
506 unp_connect2(struct socket *so, struct socket *so2)
507 {
508 struct unpcb *unp = sotounpcb(so);
509 struct unpcb *unp2;
510
511 if (so2->so_type != so->so_type)
512 return (EPROTOTYPE);
513 unp2 = sotounpcb(so2);
514 unp->unp_conn = unp2;
515 switch (so->so_type) {
516
517 case SOCK_DGRAM:
518 unp->unp_nextref = unp2->unp_refs;
519 unp2->unp_refs = unp;
520 soisconnected(so);
521 break;
522
523 case SOCK_STREAM:
524 unp2->unp_conn = unp;
525 soisconnected(so);
526 soisconnected(so2);
527 break;
528
529 default:
530 panic("unp_connect2");
531 }
532 return (0);
533 }
534
535 void
536 unp_disconnect(struct unpcb *unp)
537 {
538 struct unpcb *unp2 = unp->unp_conn;
539
540 if (unp2 == NULL)
541 return;
542 unp->unp_conn = NULL;
543 switch (unp->unp_socket->so_type) {
544
545 case SOCK_DGRAM:
546 if (unp2->unp_refs == unp)
547 unp2->unp_refs = unp->unp_nextref;
548 else {
549 unp2 = unp2->unp_refs;
550 for (;;) {
551 if (unp2 == NULL)
552 panic("unp_disconnect");
553 if (unp2->unp_nextref == unp)
554 break;
555 unp2 = unp2->unp_nextref;
556 }
557 unp2->unp_nextref = unp->unp_nextref;
558 }
559 unp->unp_nextref = NULL;
560 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
561 break;
562
563 case SOCK_STREAM:
564 soisdisconnected(unp->unp_socket);
565 unp2->unp_conn = NULL;
566 soisdisconnected(unp2->unp_socket);
567 break;
568 }
569 }
570
571 #ifdef notdef
572 unp_abort(struct unpcb *unp)
573 {
574 unp_detach(unp);
575 }
576 #endif
577
578 void
579 unp_shutdown(struct unpcb *unp)
580 {
581 struct socket *so;
582
583 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
584 (so = unp->unp_conn->unp_socket))
585 socantrcvmore(so);
586 }
587
588 void
589 unp_drop(struct unpcb *unp, int errno)
590 {
591 struct socket *so = unp->unp_socket;
592
593 so->so_error = errno;
594 unp_disconnect(unp);
595 if (so->so_head) {
596 so->so_pcb = NULL;
597 sofree(so);
598 m_freem(unp->unp_addr);
599 free(unp, M_PCB);
600 }
601 }
602
603 #ifdef notdef
604 unp_drain(void)
605 {
606
607 }
608 #endif
609
610 int
611 unp_externalize(struct mbuf *rights)
612 {
613 struct proc *p = curproc;
614 struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
615 int i, *fdp;
616 struct file **rp;
617 struct file *fp;
618 int nfds, error = 0;
619
620 nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) /
621 sizeof(struct file *);
622 rp = (struct file **)CMSG_DATA(cm);
623
624 fdp = malloc(nfds * sizeof(int), M_TEMP, M_WAITOK);
625
626 #ifdef notyet
627
628 if (p->p_cwdi->cwdi_rdir != NULL) {
629 rp = (struct file **)CMSG_DATA(cm);
630 for (i = 0; i < nfds; i++) {
631 fp = *rp++;
632
633
634
635
636
637
638 if (fp->f_type == DTYPE_VNODE) {
639 struct vnode *vp = (struct vnode *)fp->f_data;
640 if ((vp->v_type == VDIR) &&
641 !vn_isunder(vp, p->p_cwdi->cwdi_rdir, p)) {
642 error = EPERM;
643 break;
644 }
645 }
646 }
647 }
648 #endif
649
650 restart:
651 fdplock(p->p_fd);
652 if (error != 0) {
653 rp = ((struct file **)CMSG_DATA(cm));
654 for (i = 0; i < nfds; i++) {
655 fp = *rp;
656
657
658
659
660 *rp++ = NULL;
661 unp_discard(fp);
662 }
663 goto out;
664 }
665
666
667
668
669
670 rp = ((struct file **)CMSG_DATA(cm));
671 for (i = 0; i < nfds; i++) {
672 bcopy(rp, &fp, sizeof(fp));
673 rp++;
674 if ((error = fdalloc(p, 0, &fdp[i])) != 0) {
675
676
677
678 for (--i; i >= 0; i--)
679 fdremove(p->p_fd, fdp[i]);
680
681 if (error == ENOSPC) {
682 fdexpand(p);
683 error = 0;
684 } else {
685
686
687
688
689
690 error = EMSGSIZE;
691 }
692 fdpunlock(p->p_fd);
693 goto restart;
694 }
695
696
697
698
699
700
701 p->p_fd->fd_ofiles[fdp[i]] = fp;
702 }
703
704
705
706
707
708 rp = (struct file **)CMSG_DATA(cm);
709 for (i = 0; i < nfds; i++) {
710 fp = *rp++;
711 fp->f_msgcount--;
712 unp_rights--;
713 }
714
715
716
717
718
719 memcpy(CMSG_DATA(cm), fdp, nfds * sizeof(int));
720 cm->cmsg_len = CMSG_LEN(nfds * sizeof(int));
721 rights->m_len = CMSG_SPACE(nfds * sizeof(int));
722 out:
723 fdpunlock(p->p_fd);
724 free(fdp, M_TEMP);
725 return (error);
726 }
727
728 int
729 unp_internalize(struct mbuf *control, struct proc *p)
730 {
731 struct filedesc *fdp = p->p_fd;
732 struct cmsghdr *cm = mtod(control, struct cmsghdr *);
733 struct file **rp, *fp;
734 int i, error;
735 int nfds, *ip, fd, neededspace;
736
737 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
738 cm->cmsg_len != control->m_len)
739 return (EINVAL);
740 nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) / sizeof (int);
741
742
743 morespace:
744 neededspace = CMSG_SPACE(nfds * sizeof(struct file *)) -
745 control->m_len;
746 if (neededspace > M_TRAILINGSPACE(control)) {
747
748 if (control->m_flags & M_EXT)
749 return (E2BIG);
750
751
752 MCLGET(control, M_WAIT);
753 if ((control->m_flags & M_EXT) == 0)
754 return (ENOBUFS);
755
756
757 memcpy(mtod(control, char *), cm, cm->cmsg_len);
758 cm = mtod(control, struct cmsghdr *);
759 goto morespace;
760 }
761
762
763 cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct file *));
764 control->m_len = CMSG_SPACE(nfds * sizeof(struct file *));
765
766 ip = ((int *)CMSG_DATA(cm)) + nfds - 1;
767 rp = ((struct file **)CMSG_DATA(cm)) + nfds - 1;
768 for (i = 0; i < nfds; i++) {
769 bcopy(ip, &fd, sizeof fd);
770 ip--;
771 if ((fp = fd_getfile(fdp, fd)) == NULL) {
772 error = EBADF;
773 goto fail;
774 }
775 if (fp->f_count == LONG_MAX-2 ||
776 fp->f_msgcount == LONG_MAX-2) {
777 error = EDEADLK;
778 goto fail;
779 }
780 bcopy(&fp, rp, sizeof fp);
781 rp--;
782 fp->f_count++;
783 fp->f_msgcount++;
784 unp_rights++;
785 }
786 return (0);
787 fail:
788
789 for ( ; i > 0; i--) {
790 bcopy(rp, &fp, sizeof(fp));
791 rp++;
792 fp->f_count--;
793 fp->f_msgcount--;
794 unp_rights--;
795 }
796
797 return (error);
798 }
799
800 int unp_defer, unp_gcing;
801 extern struct domain unixdomain;
802
803 void
804 unp_gc(void)
805 {
806 struct file *fp, *nextfp;
807 struct socket *so;
808 struct file **extra_ref, **fpp;
809 int nunref, i;
810
811 if (unp_gcing)
812 return;
813 unp_gcing = 1;
814 unp_defer = 0;
815 LIST_FOREACH(fp, &filehead, f_list)
816 fp->f_flag &= ~(FMARK|FDEFER);
817 do {
818 LIST_FOREACH(fp, &filehead, f_list) {
819 if (fp->f_flag & FDEFER) {
820 fp->f_flag &= ~FDEFER;
821 unp_defer--;
822 } else {
823 if (fp->f_count == 0)
824 continue;
825 if (fp->f_flag & FMARK)
826 continue;
827 if (fp->f_count == fp->f_msgcount)
828 continue;
829 }
830 fp->f_flag |= FMARK;
831
832 if (fp->f_type != DTYPE_SOCKET ||
833 (so = (struct socket *)fp->f_data) == NULL)
834 continue;
835 if (so->so_proto->pr_domain != &unixdomain ||
836 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
837 continue;
838 #ifdef notdef
839 if (so->so_rcv.sb_flags & SB_LOCK) {
840
841
842
843
844
845
846
847
848
849
850 (void) sbwait(&so->so_rcv);
851 goto restart;
852 }
853 #endif
854 unp_scan(so->so_rcv.sb_mb, unp_mark, 0);
855 }
856 } while (unp_defer);
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896 extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
897 for (nunref = 0, fp = LIST_FIRST(&filehead), fpp = extra_ref;
898 fp != NULL; fp = nextfp) {
899 nextfp = LIST_NEXT(fp, f_list);
900 if (fp->f_count == 0)
901 continue;
902 if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
903 *fpp++ = fp;
904 nunref++;
905 FREF(fp);
906 fp->f_count++;
907 }
908 }
909 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
910 if ((*fpp)->f_type == DTYPE_SOCKET && (*fpp)->f_data != NULL)
911 sorflush((struct socket *)(*fpp)->f_data);
912 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
913 (void) closef(*fpp, NULL);
914 free((caddr_t)extra_ref, M_FILE);
915 unp_gcing = 0;
916 }
917
918 void
919 unp_dispose(struct mbuf *m)
920 {
921
922 if (m)
923 unp_scan(m, unp_discard, 1);
924 }
925
926 void
927 unp_scan(struct mbuf *m0, void (*op)(struct file *), int discard)
928 {
929 struct mbuf *m;
930 struct file **rp, *fp;
931 struct cmsghdr *cm;
932 int i;
933 int qfds;
934
935 while (m0) {
936 for (m = m0; m; m = m->m_next) {
937 if (m->m_type == MT_CONTROL &&
938 m->m_len >= sizeof(*cm)) {
939 cm = mtod(m, struct cmsghdr *);
940 if (cm->cmsg_level != SOL_SOCKET ||
941 cm->cmsg_type != SCM_RIGHTS)
942 continue;
943 qfds = (cm->cmsg_len - CMSG_ALIGN(sizeof *cm))
944 / sizeof(struct file *);
945 rp = (struct file **)CMSG_DATA(cm);
946 for (i = 0; i < qfds; i++) {
947 fp = *rp;
948 if (discard)
949 *rp = 0;
950 (*op)(fp);
951 rp++;
952 }
953 break;
954 }
955 }
956 m0 = m0->m_nextpkt;
957 }
958 }
959
960 void
961 unp_mark(struct file *fp)
962 {
963 if (fp == NULL)
964 return;
965
966 if (fp->f_flag & FMARK)
967 return;
968
969 if (fp->f_flag & FDEFER)
970 return;
971
972 if (fp->f_type == DTYPE_SOCKET) {
973 unp_defer++;
974 fp->f_flag |= FDEFER;
975 } else {
976 fp->f_flag |= FMARK;
977 }
978 }
979
980 void
981 unp_discard(struct file *fp)
982 {
983
984 if (fp == NULL)
985 return;
986 FREF(fp);
987 fp->f_msgcount--;
988 unp_rights--;
989 (void) closef(fp, NULL);
990 }