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