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