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