set up separate specinfo structure; allow aliased vnodes
[unix-history] / usr / src / sys / kern / uipc_usrreq.c
CommitLineData
da7c5cc6 1/*
96e6449f 2 *
f1ff9444
KM
3 * Redistribution and use in source and binary forms are permitted
4 * provided that the above copyright notice and this paragraph are
5 * duplicated in all such forms and that any documentation,
6 * advertising materials, and other materials related to such
7 * distribution and use acknowledge that the software was developed
8 * by the University of California, Berkeley. The name of the
9 * University may not be used to endorse or promote products derived
10 * from this software without specific prior written permission.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14 *
69be5b7a 15 * @(#)uipc_usrreq.c 7.13 (Berkeley) %G%
da7c5cc6 16 */
d6213d15 17
94368568 18#include "param.h"
94368568 19#include "user.h"
94368568
JB
20#include "domain.h"
21#include "protosw.h"
22#include "socket.h"
23#include "socketvar.h"
24#include "unpcb.h"
25#include "un.h"
f1ff9444
KM
26#include "vnode.h"
27#include "mount.h"
94368568
JB
28#include "file.h"
29#include "stat.h"
c4ec2128 30#include "mbuf.h" /* XXX must appear after mount.h */
d6213d15
BJ
31
32/*
33 * Unix communications domain.
88a7a62a
SL
34 *
35 * TODO:
36 * SEQPACKET, RDM
8ecea7bc 37 * rethink name space problems
88a7a62a 38 * need a proper out-of-band
d6213d15 39 */
a2aebb63 40struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
f1ff9444 41ino_t unp_vno; /* prototype for fake vnode numbers */
d6213d15
BJ
42
43/*ARGSUSED*/
88a7a62a 44uipc_usrreq(so, req, m, nam, rights)
d6213d15
BJ
45 struct socket *so;
46 int req;
88a7a62a 47 struct mbuf *m, *nam, *rights;
d6213d15
BJ
48{
49 struct unpcb *unp = sotounpcb(so);
50 register struct socket *so2;
51 int error = 0;
52
50b20c78
MK
53 if (req == PRU_CONTROL)
54 return (EOPNOTSUPP);
88a7a62a
SL
55 if (req != PRU_SEND && rights && rights->m_len) {
56 error = EOPNOTSUPP;
57 goto release;
58 }
59 if (unp == 0 && req != PRU_ATTACH) {
60 error = EINVAL;
61 goto release;
62 }
d6213d15
BJ
63 switch (req) {
64
65 case PRU_ATTACH:
66 if (unp) {
4f083fd7 67 error = EISCONN;
d6213d15
BJ
68 break;
69 }
fca5570f 70 error = unp_attach(so);
d6213d15
BJ
71 break;
72
73 case PRU_DETACH:
74 unp_detach(unp);
75 break;
76
4f083fd7
SL
77 case PRU_BIND:
78 error = unp_bind(unp, nam);
79 break;
80
81 case PRU_LISTEN:
f1ff9444 82 if (unp->unp_vnode == 0)
4f083fd7
SL
83 error = EINVAL;
84 break;
85
d6213d15 86 case PRU_CONNECT:
fca5570f 87 error = unp_connect(so, nam);
d6213d15
BJ
88 break;
89
88a7a62a 90 case PRU_CONNECT2:
d97afdcc 91 error = unp_connect2(so, (struct socket *)nam);
88a7a62a
SL
92 break;
93
d6213d15
BJ
94 case PRU_DISCONNECT:
95 unp_disconnect(unp);
96 break;
97
4f083fd7 98 case PRU_ACCEPT:
4aa1832d
MK
99 /*
100 * Pass back name of connected socket,
101 * if it was bound and we are still connected
102 * (our peer may have closed already!).
103 */
104 if (unp->unp_conn && unp->unp_conn->unp_addr) {
6c0894dd
MK
105 nam->m_len = unp->unp_conn->unp_addr->m_len;
106 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
107 mtod(nam, caddr_t), (unsigned)nam->m_len);
108 } else {
109 nam->m_len = sizeof(sun_noname);
110 *(mtod(nam, struct sockaddr *)) = sun_noname;
111 }
d6213d15
BJ
112 break;
113
114 case PRU_SHUTDOWN:
115 socantsendmore(so);
116 unp_usrclosed(unp);
117 break;
d6213d15
BJ
118
119 case PRU_RCVD:
120 switch (so->so_type) {
121
122 case SOCK_DGRAM:
123 panic("uipc 1");
5fe6f9d1 124 /*NOTREACHED*/
d6213d15 125
5fe6f9d1 126 case SOCK_STREAM:
d6213d15
BJ
127#define rcv (&so->so_rcv)
128#define snd (&so2->so_snd)
129 if (unp->unp_conn == 0)
130 break;
131 so2 = unp->unp_conn->unp_socket;
132 /*
6c0894dd 133 * Adjust backpressure on sender
d6213d15
BJ
134 * and wakeup any waiting to write.
135 */
6c0894dd
MK
136 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
137 unp->unp_mbcnt = rcv->sb_mbcnt;
138 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
139 unp->unp_cc = rcv->sb_cc;
9c40f33e 140 sowwakeup(so2);
d6213d15
BJ
141#undef snd
142#undef rcv
d6213d15
BJ
143 break;
144
145 default:
146 panic("uipc 2");
147 }
148 break;
149
150 case PRU_SEND:
6c0894dd
MK
151 if (rights) {
152 error = unp_internalize(rights);
153 if (error)
154 break;
155 }
d6213d15
BJ
156 switch (so->so_type) {
157
6c0894dd
MK
158 case SOCK_DGRAM: {
159 struct sockaddr *from;
160
fca5570f 161 if (nam) {
d6213d15
BJ
162 if (unp->unp_conn) {
163 error = EISCONN;
164 break;
165 }
fca5570f 166 error = unp_connect(so, nam);
d6213d15
BJ
167 if (error)
168 break;
169 } else {
170 if (unp->unp_conn == 0) {
171 error = ENOTCONN;
172 break;
173 }
174 }
175 so2 = unp->unp_conn->unp_socket;
6c0894dd
MK
176 if (unp->unp_addr)
177 from = mtod(unp->unp_addr, struct sockaddr *);
178 else
179 from = &sun_noname;
180 if (sbspace(&so2->so_rcv) > 0 &&
181 sbappendaddr(&so2->so_rcv, from, m, rights)) {
182 sorwakeup(so2);
183 m = 0;
184 } else
185 error = ENOBUFS;
fca5570f 186 if (nam)
4f083fd7 187 unp_disconnect(unp);
d6213d15 188 break;
6c0894dd 189 }
d6213d15
BJ
190
191 case SOCK_STREAM:
192#define rcv (&so2->so_rcv)
193#define snd (&so->so_snd)
7068721c
MK
194 if (so->so_state & SS_CANTSENDMORE) {
195 error = EPIPE;
196 break;
197 }
d6213d15
BJ
198 if (unp->unp_conn == 0)
199 panic("uipc 3");
200 so2 = unp->unp_conn->unp_socket;
201 /*
6c0894dd
MK
202 * Send to paired receive port, and then reduce
203 * send buffer hiwater marks to maintain backpressure.
d6213d15
BJ
204 * Wake up readers.
205 */
6c0894dd 206 if (rights)
8011f5df 207 (void)sbappendrights(rcv, m, rights);
6c0894dd
MK
208 else
209 sbappend(rcv, m);
210 snd->sb_mbmax -=
211 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
212 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
213 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
214 unp->unp_conn->unp_cc = rcv->sb_cc;
9c40f33e
MK
215 sorwakeup(so2);
216 m = 0;
d6213d15
BJ
217#undef snd
218#undef rcv
219 break;
220
221 default:
222 panic("uipc 4");
223 }
224 break;
225
226 case PRU_ABORT:
227 unp_drop(unp, ECONNABORTED);
228 break;
229
bfd4e82c
MK
230 case PRU_SENSE:
231 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
232 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
233 so2 = unp->unp_conn->unp_socket;
234 ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
235 }
0abd16a9 236 ((struct stat *) m)->st_dev = NODEV;
f1ff9444
KM
237 if (unp->unp_vno == 0)
238 unp->unp_vno = unp_vno++;
239 ((struct stat *) m)->st_ino = unp->unp_vno;
bfd4e82c 240 return (0);
d6213d15
BJ
241
242 case PRU_RCVOOB:
913b2f19 243 return (EOPNOTSUPP);
d6213d15
BJ
244
245 case PRU_SENDOOB:
9c40f33e 246 error = EOPNOTSUPP;
d6213d15
BJ
247 break;
248
249 case PRU_SOCKADDR:
e14f40ae
MK
250 if (unp->unp_addr) {
251 nam->m_len = unp->unp_addr->m_len;
252 bcopy(mtod(unp->unp_addr, caddr_t),
253 mtod(nam, caddr_t), (unsigned)nam->m_len);
254 } else
255 nam->m_len = 0;
d6213d15
BJ
256 break;
257
a7343092 258 case PRU_PEERADDR:
bbd1716e
MK
259 if (unp->unp_conn && unp->unp_conn->unp_addr) {
260 nam->m_len = unp->unp_conn->unp_addr->m_len;
261 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
336a1154 262 mtod(nam, caddr_t), (unsigned)nam->m_len);
e14f40ae
MK
263 } else
264 nam->m_len = 0;
a7343092
SL
265 break;
266
d6213d15
BJ
267 case PRU_SLOWTIMO:
268 break;
269
270 default:
271 panic("piusrreq");
272 }
88a7a62a
SL
273release:
274 if (m)
275 m_freem(m);
e14b8185 276 return (error);
d6213d15
BJ
277}
278
bfd4e82c 279/*
6c0894dd
MK
280 * Both send and receive buffers are allocated PIPSIZ bytes of buffering
281 * for stream sockets, although the total for sender and receiver is
282 * actually only PIPSIZ.
bfd4e82c
MK
283 * Datagram sockets really use the sendspace as the maximum datagram size,
284 * and don't really want to reserve the sendspace. Their recvspace should
285 * be large enough for at least one max-size datagram plus address.
286 */
287#define PIPSIZ 4096
4f5156ea
MK
288u_long unpst_sendspace = PIPSIZ;
289u_long unpst_recvspace = PIPSIZ;
290u_long unpdg_sendspace = 2*1024; /* really max datagram size */
291u_long unpdg_recvspace = 4*1024;
d6213d15 292
6c0894dd
MK
293int unp_rights; /* file descriptors in flight */
294
4f083fd7 295unp_attach(so)
d6213d15 296 struct socket *so;
d6213d15 297{
4f083fd7 298 register struct mbuf *m;
d6213d15 299 register struct unpcb *unp;
d6213d15
BJ
300 int error;
301
4f5156ea
MK
302 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
303 switch (so->so_type) {
bfd4e82c 304
4f5156ea
MK
305 case SOCK_STREAM:
306 error = soreserve(so, unpst_sendspace, unpst_recvspace);
307 break;
bfd4e82c 308
4f5156ea
MK
309 case SOCK_DGRAM:
310 error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
311 break;
312 }
313 if (error)
314 return (error);
bfd4e82c 315 }
cce93e4b 316 m = m_getclr(M_DONTWAIT, MT_PCB);
5fe6f9d1
SL
317 if (m == NULL)
318 return (ENOBUFS);
d6213d15
BJ
319 unp = mtod(m, struct unpcb *);
320 so->so_pcb = (caddr_t)unp;
321 unp->unp_socket = so;
d6213d15 322 return (0);
d6213d15
BJ
323}
324
d6213d15 325unp_detach(unp)
4f083fd7 326 register struct unpcb *unp;
d6213d15
BJ
327{
328
f1ff9444
KM
329 if (unp->unp_vnode) {
330 unp->unp_vnode->v_socket = 0;
331 vrele(unp->unp_vnode);
332 unp->unp_vnode = 0;
d6213d15
BJ
333 }
334 if (unp->unp_conn)
335 unp_disconnect(unp);
336 while (unp->unp_refs)
337 unp_drop(unp->unp_refs, ECONNRESET);
338 soisdisconnected(unp->unp_socket);
339 unp->unp_socket->so_pcb = 0;
6c0894dd 340 m_freem(unp->unp_addr);
4f083fd7 341 (void) m_free(dtom(unp));
6c0894dd
MK
342 if (unp_rights)
343 unp_gc();
d6213d15
BJ
344}
345
4f083fd7 346unp_bind(unp, nam)
d6213d15 347 struct unpcb *unp;
4f083fd7 348 struct mbuf *nam;
d6213d15 349{
4f083fd7 350 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 351 register struct vnode *vp;
715baff1 352 register struct nameidata *ndp = &u.u_nd;
f1ff9444 353 struct vattr vattr;
4f083fd7 354 int error;
d6213d15 355
715baff1 356 ndp->ni_dirp = soun->sun_path;
e0d8abb8 357 if (unp->unp_vnode != NULL)
88a7a62a 358 return (EINVAL);
61375223
MK
359 if (nam->m_len == MLEN) {
360 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
361 return (EINVAL);
362 } else
363 *(mtod(nam, caddr_t) + nam->m_len) = 0;
88a7a62a 364/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
f1ff9444 365 ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
715baff1 366 ndp->ni_segflg = UIO_SYSSPACE;
f1ff9444 367 if (error = namei(ndp))
f3bb1ae7 368 return (error);
f1ff9444
KM
369 vp = ndp->ni_vp;
370 if (vp != NULL) {
c4ec2128 371 VOP_ABORTOP(ndp);
f1ff9444 372 return (EADDRINUSE);
f3bb1ae7 373 }
f1ff9444
KM
374 vattr_null(&vattr);
375 vattr.va_type = VSOCK;
376 vattr.va_mode = 0777;
c4ec2128 377 if (error = VOP_CREATE(ndp, &vattr))
d6213d15 378 return (error);
f1ff9444
KM
379 vp = ndp->ni_vp;
380 vp->v_socket = unp->unp_socket;
381 unp->unp_vnode = vp;
6c0894dd 382 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
c4ec2128 383 VOP_UNLOCK(vp);
d6213d15
BJ
384 return (0);
385}
386
4f083fd7 387unp_connect(so, nam)
d6213d15 388 struct socket *so;
4f083fd7 389 struct mbuf *nam;
d6213d15 390{
4f083fd7 391 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 392 register struct vnode *vp;
e14f40ae 393 register struct socket *so2, *so3;
715baff1 394 register struct nameidata *ndp = &u.u_nd;
e14f40ae
MK
395 struct unpcb *unp2, *unp3;
396 int error;
d6213d15 397
715baff1 398 ndp->ni_dirp = soun->sun_path;
61375223
MK
399 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
400 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
401 return (EMSGSIZE);
402 } else
403 *(mtod(nam, caddr_t) + nam->m_len) = 0;
c4ec2128 404 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1 405 ndp->ni_segflg = UIO_SYSSPACE;
f1ff9444
KM
406 if (error = namei(ndp))
407 return (error);
408 vp = ndp->ni_vp;
f1ff9444 409 if (vp->v_type != VSOCK) {
d6213d15
BJ
410 error = ENOTSOCK;
411 goto bad;
412 }
6a1c9219
KM
413 if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))
414 goto bad;
f1ff9444 415 so2 = vp->v_socket;
d6213d15
BJ
416 if (so2 == 0) {
417 error = ECONNREFUSED;
418 goto bad;
419 }
5a48956d
SL
420 if (so->so_type != so2->so_type) {
421 error = EPROTOTYPE;
422 goto bad;
423 }
e14f40ae
MK
424 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
425 if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
426 (so3 = sonewconn(so2)) == 0) {
427 error = ECONNREFUSED;
428 goto bad;
429 }
430 unp2 = sotounpcb(so2);
431 unp3 = sotounpcb(so3);
432 if (unp2->unp_addr)
a2aebb63
KS
433 unp3->unp_addr =
434 m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
e14f40ae 435 so2 = so3;
5a48956d 436 }
d97afdcc 437 error = unp_connect2(so, so2);
88a7a62a 438bad:
c4ec2128 439 vput(vp);
88a7a62a
SL
440 return (error);
441}
442
d97afdcc 443unp_connect2(so, so2)
88a7a62a 444 register struct socket *so;
88a7a62a
SL
445 register struct socket *so2;
446{
447 register struct unpcb *unp = sotounpcb(so);
448 register struct unpcb *unp2;
449
450 if (so2->so_type != so->so_type)
451 return (EPROTOTYPE);
ccffacbd
SL
452 unp2 = sotounpcb(so2);
453 unp->unp_conn = unp2;
d6213d15
BJ
454 switch (so->so_type) {
455
456 case SOCK_DGRAM:
d6213d15
BJ
457 unp->unp_nextref = unp2->unp_refs;
458 unp2->unp_refs = unp;
9c40f33e 459 soisconnected(so);
d6213d15
BJ
460 break;
461
462 case SOCK_STREAM:
4f083fd7 463 unp2->unp_conn = unp;
ccffacbd
SL
464 soisconnected(so2);
465 soisconnected(so);
d6213d15
BJ
466 break;
467
468 default:
88a7a62a 469 panic("unp_connect2");
d6213d15 470 }
d6213d15 471 return (0);
d6213d15 472}
4f083fd7
SL
473
474unp_disconnect(unp)
475 struct unpcb *unp;
476{
477 register struct unpcb *unp2 = unp->unp_conn;
478
479 if (unp2 == 0)
480 return;
481 unp->unp_conn = 0;
4f083fd7
SL
482 switch (unp->unp_socket->so_type) {
483
484 case SOCK_DGRAM:
485 if (unp2->unp_refs == unp)
486 unp2->unp_refs = unp->unp_nextref;
487 else {
488 unp2 = unp2->unp_refs;
489 for (;;) {
490 if (unp2 == 0)
491 panic("unp_disconnect");
492 if (unp2->unp_nextref == unp)
493 break;
494 unp2 = unp2->unp_nextref;
495 }
496 unp2->unp_nextref = unp->unp_nextref;
497 }
498 unp->unp_nextref = 0;
c5935bca 499 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4f083fd7
SL
500 break;
501
502 case SOCK_STREAM:
ccffacbd 503 soisdisconnected(unp->unp_socket);
4f083fd7
SL
504 unp2->unp_conn = 0;
505 soisdisconnected(unp2->unp_socket);
4f083fd7
SL
506 break;
507 }
508}
509
88a7a62a 510#ifdef notdef
4f083fd7
SL
511unp_abort(unp)
512 struct unpcb *unp;
513{
514
515 unp_detach(unp);
516}
88a7a62a 517#endif
4f083fd7
SL
518
519/*ARGSUSED*/
520unp_usrclosed(unp)
521 struct unpcb *unp;
522{
523
524}
525
526unp_drop(unp, errno)
527 struct unpcb *unp;
528 int errno;
529{
d12671e0 530 struct socket *so = unp->unp_socket;
4f083fd7 531
d12671e0 532 so->so_error = errno;
4f083fd7 533 unp_disconnect(unp);
d12671e0
MK
534 if (so->so_head) {
535 so->so_pcb = (caddr_t) 0;
6c0894dd 536 m_freem(unp->unp_addr);
d12671e0
MK
537 (void) m_free(dtom(unp));
538 sofree(so);
539 }
4f083fd7
SL
540}
541
88a7a62a 542#ifdef notdef
4f083fd7
SL
543unp_drain()
544{
545
546}
88a7a62a
SL
547#endif
548
549unp_externalize(rights)
550 struct mbuf *rights;
551{
552 int newfds = rights->m_len / sizeof (int);
553 register int i;
554 register struct file **rp = mtod(rights, struct file **);
555 register struct file *fp;
556 int f;
557
558 if (newfds > ufavail()) {
559 for (i = 0; i < newfds; i++) {
560 fp = *rp;
561 unp_discard(fp);
562 *rp++ = 0;
563 }
564 return (EMSGSIZE);
565 }
566 for (i = 0; i < newfds; i++) {
f1ff9444 567 if (ufalloc(0, &f))
88a7a62a
SL
568 panic("unp_externalize");
569 fp = *rp;
570 u.u_ofile[f] = fp;
571 fp->f_msgcount--;
6c0894dd 572 unp_rights--;
bb3b4851 573 *(int *)rp++ = f;
88a7a62a
SL
574 }
575 return (0);
576}
577
578unp_internalize(rights)
579 struct mbuf *rights;
580{
581 register struct file **rp;
582 int oldfds = rights->m_len / sizeof (int);
c4ec2128 583 register int i, fd;
88a7a62a
SL
584 register struct file *fp;
585
586 rp = mtod(rights, struct file **);
c4ec2128
KM
587 for (i = 0; i < oldfds; i++) {
588 fd = *(int *)rp++;
589 if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL)
88a7a62a 590 return (EBADF);
c4ec2128 591 }
88a7a62a 592 rp = mtod(rights, struct file **);
44eb2da3 593 for (i = 0; i < oldfds; i++) {
c4ec2128 594 fp = u.u_ofile[*(int *)rp];
88a7a62a
SL
595 *rp++ = fp;
596 fp->f_count++;
597 fp->f_msgcount++;
6c0894dd 598 unp_rights++;
88a7a62a
SL
599 }
600 return (0);
601}
602
603int unp_defer, unp_gcing;
604int unp_mark();
261a8548 605extern struct domain unixdomain;
88a7a62a
SL
606
607unp_gc()
608{
609 register struct file *fp;
610 register struct socket *so;
611
612 if (unp_gcing)
613 return;
614 unp_gcing = 1;
615restart:
616 unp_defer = 0;
617 for (fp = file; fp < fileNFILE; fp++)
618 fp->f_flag &= ~(FMARK|FDEFER);
619 do {
620 for (fp = file; fp < fileNFILE; fp++) {
621 if (fp->f_count == 0)
622 continue;
623 if (fp->f_flag & FDEFER) {
624 fp->f_flag &= ~FDEFER;
625 unp_defer--;
626 } else {
627 if (fp->f_flag & FMARK)
628 continue;
629 if (fp->f_count == fp->f_msgcount)
630 continue;
631 fp->f_flag |= FMARK;
632 }
aa5945aa
MK
633 if (fp->f_type != DTYPE_SOCKET ||
634 (so = (struct socket *)fp->f_data) == 0)
88a7a62a 635 continue;
261a8548 636 if (so->so_proto->pr_domain != &unixdomain ||
c5935bca 637 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
88a7a62a
SL
638 continue;
639 if (so->so_rcv.sb_flags & SB_LOCK) {
640 sbwait(&so->so_rcv);
641 goto restart;
642 }
643 unp_scan(so->so_rcv.sb_mb, unp_mark);
644 }
645 } while (unp_defer);
646 for (fp = file; fp < fileNFILE; fp++) {
647 if (fp->f_count == 0)
648 continue;
6c0894dd
MK
649 if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
650 while (fp->f_msgcount)
651 unp_discard(fp);
88a7a62a
SL
652 }
653 unp_gcing = 0;
654}
655
261a8548
MK
656unp_dispose(m)
657 struct mbuf *m;
658{
659 int unp_discard();
660
148703ec
MK
661 if (m)
662 unp_scan(m, unp_discard);
261a8548
MK
663}
664
665unp_scan(m0, op)
666 register struct mbuf *m0;
88a7a62a
SL
667 int (*op)();
668{
261a8548 669 register struct mbuf *m;
88a7a62a
SL
670 register struct file **rp;
671 register int i;
148703ec 672 int qfds;
261a8548
MK
673
674 while (m0) {
675 for (m = m0; m; m = m->m_next)
676 if (m->m_type == MT_RIGHTS && m->m_len) {
677 qfds = m->m_len / sizeof (struct file *);
678 rp = mtod(m, struct file **);
679 for (i = 0; i < qfds; i++)
680 (*op)(*rp++);
681 break; /* XXX, but saves time */
682 }
148703ec 683 m0 = m0->m_act;
88a7a62a 684 }
88a7a62a
SL
685}
686
687unp_mark(fp)
688 struct file *fp;
689{
690
691 if (fp->f_flag & FMARK)
692 return;
693 unp_defer++;
694 fp->f_flag |= (FMARK|FDEFER);
695}
696
697unp_discard(fp)
698 struct file *fp;
699{
700
701 fp->f_msgcount--;
6c0894dd 702 unp_rights--;
69be5b7a 703 (void) closef(fp);
88a7a62a 704}