do not set soft limit higher than new hard limit (net2/sys/8)
[unix-history] / usr / src / sys / kern / uipc_usrreq.c
CommitLineData
da7c5cc6 1/*
96e6449f 2 *
dbf0c423 3 * %sccs.include.redist.c%
f1ff9444 4 *
224df21f 5 * @(#)uipc_usrreq.c 7.31 (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;
224df21f
KM
304
305 default:
306 panic("unp_attach");
4f5156ea
MK
307 }
308 if (error)
309 return (error);
bfd4e82c 310 }
cce93e4b 311 m = m_getclr(M_DONTWAIT, MT_PCB);
5fe6f9d1
SL
312 if (m == NULL)
313 return (ENOBUFS);
d6213d15
BJ
314 unp = mtod(m, struct unpcb *);
315 so->so_pcb = (caddr_t)unp;
316 unp->unp_socket = so;
d6213d15 317 return (0);
d6213d15
BJ
318}
319
d6213d15 320unp_detach(unp)
4f083fd7 321 register struct unpcb *unp;
d6213d15
BJ
322{
323
f1ff9444
KM
324 if (unp->unp_vnode) {
325 unp->unp_vnode->v_socket = 0;
326 vrele(unp->unp_vnode);
327 unp->unp_vnode = 0;
d6213d15
BJ
328 }
329 if (unp->unp_conn)
330 unp_disconnect(unp);
331 while (unp->unp_refs)
332 unp_drop(unp->unp_refs, ECONNRESET);
333 soisdisconnected(unp->unp_socket);
334 unp->unp_socket->so_pcb = 0;
6c0894dd 335 m_freem(unp->unp_addr);
4f083fd7 336 (void) m_free(dtom(unp));
6c0894dd
MK
337 if (unp_rights)
338 unp_gc();
d6213d15
BJ
339}
340
a1a7e02b 341unp_bind(unp, nam, p)
d6213d15 342 struct unpcb *unp;
4f083fd7 343 struct mbuf *nam;
a1a7e02b 344 struct proc *p;
d6213d15 345{
4f083fd7 346 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 347 register struct vnode *vp;
f1ff9444 348 struct vattr vattr;
4f083fd7 349 int error;
8429d022 350 struct nameidata nd;
d6213d15 351
56b1696d
KM
352 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
353 soun->sun_path, p);
e0d8abb8 354 if (unp->unp_vnode != NULL)
88a7a62a 355 return (EINVAL);
61375223
MK
356 if (nam->m_len == MLEN) {
357 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
358 return (EINVAL);
359 } else
360 *(mtod(nam, caddr_t) + nam->m_len) = 0;
88a7a62a 361/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
56b1696d 362 if (error = namei(&nd))
f3bb1ae7 363 return (error);
56b1696d 364 vp = nd.ni_vp;
f1ff9444 365 if (vp != NULL) {
56b1696d
KM
366 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
367 if (nd.ni_dvp == vp)
368 vrele(nd.ni_dvp);
39d703d6 369 else
56b1696d 370 vput(nd.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;
56b1696d
KM
377 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
378 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
d6213d15 379 return (error);
56b1696d 380 vp = nd.ni_vp;
f1ff9444
KM
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
a1a7e02b 388unp_connect(so, nam, p)
d6213d15 389 struct socket *so;
4f083fd7 390 struct mbuf *nam;
a1a7e02b 391 struct proc *p;
d6213d15 392{
4f083fd7 393 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 394 register struct vnode *vp;
e14f40ae 395 register struct socket *so2, *so3;
e14f40ae
MK
396 struct unpcb *unp2, *unp3;
397 int error;
8429d022 398 struct nameidata nd;
d6213d15 399
56b1696d 400 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
61375223
MK
401 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
402 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
403 return (EMSGSIZE);
404 } else
405 *(mtod(nam, caddr_t) + nam->m_len) = 0;
56b1696d 406 if (error = namei(&nd))
f1ff9444 407 return (error);
56b1696d 408 vp = nd.ni_vp;
f1ff9444 409 if (vp->v_type != VSOCK) {
d6213d15
BJ
410 error = ENOTSOCK;
411 goto bad;
412 }
a1a7e02b 413 if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
6a1c9219 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 ||
0293c204 426 (so3 = sonewconn(so2, 0)) == 0) {
e14f40ae
MK
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 464 soisconnected(so);
0293c204 465 soisconnected(so2);
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 518
5b09b219 519unp_shutdown(unp)
4f083fd7
SL
520 struct unpcb *unp;
521{
5b09b219 522 struct socket *so;
4f083fd7 523
5b09b219
MK
524 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
525 (so = unp->unp_conn->unp_socket))
526 socantrcvmore(so);
4f083fd7
SL
527}
528
529unp_drop(unp, errno)
530 struct unpcb *unp;
531 int errno;
532{
d12671e0 533 struct socket *so = unp->unp_socket;
4f083fd7 534
d12671e0 535 so->so_error = errno;
4f083fd7 536 unp_disconnect(unp);
d12671e0
MK
537 if (so->so_head) {
538 so->so_pcb = (caddr_t) 0;
6c0894dd 539 m_freem(unp->unp_addr);
d12671e0
MK
540 (void) m_free(dtom(unp));
541 sofree(so);
542 }
4f083fd7
SL
543}
544
88a7a62a 545#ifdef notdef
4f083fd7
SL
546unp_drain()
547{
548
549}
88a7a62a
SL
550#endif
551
552unp_externalize(rights)
553 struct mbuf *rights;
554{
8429d022 555 struct proc *p = curproc; /* XXX */
88a7a62a 556 register int i;
0293c204
KS
557 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
558 register struct file **rp = (struct file **)(cm + 1);
88a7a62a 559 register struct file *fp;
0293c204 560 int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
88a7a62a
SL
561 int f;
562
8429d022 563 if (fdavail(p, newfds)) {
88a7a62a
SL
564 for (i = 0; i < newfds; i++) {
565 fp = *rp;
566 unp_discard(fp);
567 *rp++ = 0;
568 }
569 return (EMSGSIZE);
570 }
571 for (i = 0; i < newfds; i++) {
8429d022 572 if (fdalloc(p, 0, &f))
88a7a62a
SL
573 panic("unp_externalize");
574 fp = *rp;
a52e940f 575 p->p_fd->fd_ofiles[f] = fp;
88a7a62a 576 fp->f_msgcount--;
6c0894dd 577 unp_rights--;
bb3b4851 578 *(int *)rp++ = f;
88a7a62a
SL
579 }
580 return (0);
581}
582
a1a7e02b 583unp_internalize(control, p)
d83a7d17 584 struct mbuf *control;
a1a7e02b 585 struct proc *p;
88a7a62a 586{
a1a7e02b 587 struct filedesc *fdp = p->p_fd;
d83a7d17 588 register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
88a7a62a 589 register struct file **rp;
88a7a62a 590 register struct file *fp;
d83a7d17
MK
591 register int i, fd;
592 int oldfds;
88a7a62a 593
d83a7d17
MK
594 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
595 cm->cmsg_len != control->m_len)
0293c204
KS
596 return (EINVAL);
597 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
0293c204 598 rp = (struct file **)(cm + 1);
c4ec2128
KM
599 for (i = 0; i < oldfds; i++) {
600 fd = *(int *)rp++;
a52e940f
MK
601 if ((unsigned)fd >= fdp->fd_nfiles ||
602 fdp->fd_ofiles[fd] == NULL)
88a7a62a 603 return (EBADF);
c4ec2128 604 }
0293c204 605 rp = (struct file **)(cm + 1);
44eb2da3 606 for (i = 0; i < oldfds; i++) {
a52e940f 607 fp = fdp->fd_ofiles[*(int *)rp];
88a7a62a
SL
608 *rp++ = fp;
609 fp->f_count++;
610 fp->f_msgcount++;
6c0894dd 611 unp_rights++;
88a7a62a
SL
612 }
613 return (0);
614}
615
616int unp_defer, unp_gcing;
617int unp_mark();
261a8548 618extern struct domain unixdomain;
88a7a62a
SL
619
620unp_gc()
621{
622 register struct file *fp;
623 register struct socket *so;
624
625 if (unp_gcing)
626 return;
627 unp_gcing = 1;
628restart:
629 unp_defer = 0;
d7a29601 630 for (fp = filehead; fp; fp = fp->f_filef)
88a7a62a
SL
631 fp->f_flag &= ~(FMARK|FDEFER);
632 do {
d7a29601 633 for (fp = filehead; fp; fp = fp->f_filef) {
88a7a62a
SL
634 if (fp->f_count == 0)
635 continue;
636 if (fp->f_flag & FDEFER) {
637 fp->f_flag &= ~FDEFER;
638 unp_defer--;
639 } else {
640 if (fp->f_flag & FMARK)
641 continue;
642 if (fp->f_count == fp->f_msgcount)
643 continue;
644 fp->f_flag |= FMARK;
645 }
aa5945aa
MK
646 if (fp->f_type != DTYPE_SOCKET ||
647 (so = (struct socket *)fp->f_data) == 0)
88a7a62a 648 continue;
261a8548 649 if (so->so_proto->pr_domain != &unixdomain ||
c5935bca 650 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
88a7a62a 651 continue;
5b09b219 652#ifdef notdef
88a7a62a 653 if (so->so_rcv.sb_flags & SB_LOCK) {
5b09b219
MK
654 /*
655 * This is problematical; it's not clear
656 * we need to wait for the sockbuf to be
657 * unlocked (on a uniprocessor, at least),
658 * and it's also not clear what to do
659 * if sbwait returns an error due to receipt
660 * of a signal. If sbwait does return
661 * an error, we'll go into an infinite
662 * loop. Delete all of this for now.
663 */
664 (void) sbwait(&so->so_rcv);
88a7a62a
SL
665 goto restart;
666 }
5b09b219 667#endif
88a7a62a
SL
668 unp_scan(so->so_rcv.sb_mb, unp_mark);
669 }
670 } while (unp_defer);
d7a29601 671 for (fp = filehead; fp; fp = fp->f_filef) {
88a7a62a
SL
672 if (fp->f_count == 0)
673 continue;
6c0894dd
MK
674 if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
675 while (fp->f_msgcount)
676 unp_discard(fp);
88a7a62a
SL
677 }
678 unp_gcing = 0;
679}
680
261a8548
MK
681unp_dispose(m)
682 struct mbuf *m;
683{
684 int unp_discard();
685
148703ec
MK
686 if (m)
687 unp_scan(m, unp_discard);
261a8548
MK
688}
689
690unp_scan(m0, op)
691 register struct mbuf *m0;
88a7a62a
SL
692 int (*op)();
693{
261a8548 694 register struct mbuf *m;
88a7a62a 695 register struct file **rp;
d83a7d17 696 register struct cmsghdr *cm;
88a7a62a 697 register int i;
148703ec 698 int qfds;
261a8548
MK
699
700 while (m0) {
701 for (m = m0; m; m = m->m_next)
d83a7d17
MK
702 if (m->m_type == MT_CONTROL &&
703 m->m_len >= sizeof(*cm)) {
0293c204 704 cm = mtod(m, struct cmsghdr *);
d83a7d17
MK
705 if (cm->cmsg_level != SOL_SOCKET ||
706 cm->cmsg_type != SCM_RIGHTS)
707 continue;
0293c204
KS
708 qfds = (cm->cmsg_len - sizeof *cm)
709 / sizeof (struct file *);
710 rp = (struct file **)(cm + 1);
261a8548
MK
711 for (i = 0; i < qfds; i++)
712 (*op)(*rp++);
713 break; /* XXX, but saves time */
714 }
148703ec 715 m0 = m0->m_act;
88a7a62a 716 }
88a7a62a
SL
717}
718
719unp_mark(fp)
720 struct file *fp;
721{
722
723 if (fp->f_flag & FMARK)
724 return;
725 unp_defer++;
726 fp->f_flag |= (FMARK|FDEFER);
727}
728
729unp_discard(fp)
730 struct file *fp;
731{
732
733 fp->f_msgcount--;
6c0894dd 734 unp_rights--;
84096e8e 735 (void) closef(fp, (struct proc *)NULL);
88a7a62a 736}