delete VERBOSE #ifdef's
[unix-history] / usr / src / sys / kern / uipc_usrreq.c
CommitLineData
da7c5cc6 1/*
96e6449f 2 *
dbf0c423 3 * %sccs.include.redist.c%
f1ff9444 4 *
cb9bf523 5 * @(#)uipc_usrreq.c 7.37 (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{
4f083fd7 347 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 348 register struct vnode *vp;
f1ff9444 349 struct vattr vattr;
4f083fd7 350 int error;
8429d022 351 struct nameidata nd;
d6213d15 352
56b1696d
KM
353 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
354 soun->sun_path, p);
e0d8abb8 355 if (unp->unp_vnode != NULL)
88a7a62a 356 return (EINVAL);
61375223
MK
357 if (nam->m_len == MLEN) {
358 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
359 return (EINVAL);
360 } else
361 *(mtod(nam, caddr_t) + nam->m_len) = 0;
88a7a62a 362/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
56b1696d 363 if (error = namei(&nd))
f3bb1ae7 364 return (error);
56b1696d 365 vp = nd.ni_vp;
f1ff9444 366 if (vp != NULL) {
56b1696d
KM
367 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
368 if (nd.ni_dvp == vp)
369 vrele(nd.ni_dvp);
39d703d6 370 else
56b1696d 371 vput(nd.ni_dvp);
66955caf 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;
56b1696d
KM
378 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
379 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
d6213d15 380 return (error);
56b1696d 381 vp = nd.ni_vp;
f1ff9444
KM
382 vp->v_socket = unp->unp_socket;
383 unp->unp_vnode = vp;
6c0894dd 384 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
c4ec2128 385 VOP_UNLOCK(vp);
d6213d15
BJ
386 return (0);
387}
388
a1a7e02b 389unp_connect(so, nam, p)
d6213d15 390 struct socket *so;
4f083fd7 391 struct mbuf *nam;
a1a7e02b 392 struct proc *p;
d6213d15 393{
4f083fd7 394 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
f1ff9444 395 register struct vnode *vp;
e14f40ae 396 register struct socket *so2, *so3;
e14f40ae
MK
397 struct unpcb *unp2, *unp3;
398 int error;
8429d022 399 struct nameidata nd;
d6213d15 400
56b1696d 401 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
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;
56b1696d 407 if (error = namei(&nd))
f1ff9444 408 return (error);
56b1696d 409 vp = nd.ni_vp;
f1ff9444 410 if (vp->v_type != VSOCK) {
d6213d15
BJ
411 error = ENOTSOCK;
412 goto bad;
413 }
a1a7e02b 414 if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
6a1c9219 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 519
5b09b219 520unp_shutdown(unp)
4f083fd7
SL
521 struct unpcb *unp;
522{
5b09b219 523 struct socket *so;
4f083fd7 524
5b09b219
MK
525 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
526 (so = unp->unp_conn->unp_socket))
527 socantrcvmore(so);
4f083fd7
SL
528}
529
530unp_drop(unp, errno)
531 struct unpcb *unp;
532 int errno;
533{
d12671e0 534 struct socket *so = unp->unp_socket;
4f083fd7 535
d12671e0 536 so->so_error = errno;
4f083fd7 537 unp_disconnect(unp);
d12671e0
MK
538 if (so->so_head) {
539 so->so_pcb = (caddr_t) 0;
6c0894dd 540 m_freem(unp->unp_addr);
d12671e0
MK
541 (void) m_free(dtom(unp));
542 sofree(so);
543 }
4f083fd7
SL
544}
545
88a7a62a 546#ifdef notdef
4f083fd7
SL
547unp_drain()
548{
549
550}
88a7a62a
SL
551#endif
552
553unp_externalize(rights)
554 struct mbuf *rights;
555{
8429d022 556 struct proc *p = curproc; /* XXX */
88a7a62a 557 register int i;
0293c204
KS
558 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
559 register struct file **rp = (struct file **)(cm + 1);
88a7a62a 560 register struct file *fp;
0293c204 561 int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
88a7a62a
SL
562 int f;
563
58073841 564 if (!fdavail(p, newfds)) {
88a7a62a
SL
565 for (i = 0; i < newfds; i++) {
566 fp = *rp;
567 unp_discard(fp);
568 *rp++ = 0;
569 }
570 return (EMSGSIZE);
571 }
572 for (i = 0; i < newfds; i++) {
8429d022 573 if (fdalloc(p, 0, &f))
88a7a62a
SL
574 panic("unp_externalize");
575 fp = *rp;
a52e940f 576 p->p_fd->fd_ofiles[f] = fp;
88a7a62a 577 fp->f_msgcount--;
6c0894dd 578 unp_rights--;
bb3b4851 579 *(int *)rp++ = f;
88a7a62a
SL
580 }
581 return (0);
582}
583
a1a7e02b 584unp_internalize(control, p)
d83a7d17 585 struct mbuf *control;
a1a7e02b 586 struct proc *p;
88a7a62a 587{
a1a7e02b 588 struct filedesc *fdp = p->p_fd;
d83a7d17 589 register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
88a7a62a 590 register struct file **rp;
88a7a62a 591 register struct file *fp;
d83a7d17
MK
592 register int i, fd;
593 int oldfds;
88a7a62a 594
d83a7d17
MK
595 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
596 cm->cmsg_len != control->m_len)
0293c204
KS
597 return (EINVAL);
598 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
0293c204 599 rp = (struct file **)(cm + 1);
c4ec2128
KM
600 for (i = 0; i < oldfds; i++) {
601 fd = *(int *)rp++;
a52e940f
MK
602 if ((unsigned)fd >= fdp->fd_nfiles ||
603 fdp->fd_ofiles[fd] == NULL)
88a7a62a 604 return (EBADF);
c4ec2128 605 }
0293c204 606 rp = (struct file **)(cm + 1);
44eb2da3 607 for (i = 0; i < oldfds; i++) {
a52e940f 608 fp = fdp->fd_ofiles[*(int *)rp];
88a7a62a
SL
609 *rp++ = fp;
610 fp->f_count++;
611 fp->f_msgcount++;
6c0894dd 612 unp_rights++;
88a7a62a
SL
613 }
614 return (0);
615}
616
617int unp_defer, unp_gcing;
618int unp_mark();
261a8548 619extern struct domain unixdomain;
88a7a62a
SL
620
621unp_gc()
622{
902505c0 623 register struct file *fp, *nextfp;
88a7a62a 624 register struct socket *so;
cb9bf523
KM
625 struct file **extra_ref, **fpp;
626 int nunref, i;
88a7a62a
SL
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);
cb9bf523
KM
674 /*
675 * We grab an extra reference to each of the file table entries
676 * that are not otherwise accessible and then free the rights
677 * that are stored in messages on them.
678 *
679 * The bug in the orginal code is a little tricky, so I'll describe
680 * what's wrong with it here.
681 *
682 * It is incorrect to simply unp_discard each entry for f_msgcount
683 * times -- consider the case of sockets A and B that contain
684 * references to each other. On a last close of some other socket,
685 * we trigger a gc since the number of outstanding rights (unp_rights)
686 * is non-zero. If during the sweep phase the gc code un_discards,
687 * we end up doing a (full) closef on the descriptor. A closef on A
688 * results in the following chain. Closef calls soo_close, which
689 * calls soclose. Soclose calls first (through the switch
690 * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply
691 * returns because the previous instance had set unp_gcing, and
692 * we return all the way back to soclose, which marks the socket
693 * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush
694 * to free up the rights that are queued in messages on the socket A,
695 * i.e., the reference on B. The sorflush calls via the dom_dispose
696 * switch unp_dispose, which unp_scans with unp_discard. This second
697 * instance of unp_discard just calls closef on B.
698 *
699 * Well, a similar chain occurs on B, resulting in a sorflush on B,
700 * which results in another closef on A. Unfortunately, A is already
701 * being closed, and the descriptor has already been marked with
702 * SS_NOFDREF, and soclose panics at this point.
703 *
704 * Here, we first take an extra reference to each inaccessible
705 * descriptor. Then, we call sorflush ourself, since we know
706 * it is a Unix domain socket anyhow. After we destroy all the
707 * rights carried in messages, we do a last closef to get rid
708 * of our extra reference. This is the last close, and the
709 * unp_detach etc will shut down the socket.
710 *
711 * 91/09/19, bsy@cs.cmu.edu
712 */
713 extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
714 for (nunref = 0, fp = filehead, fpp = extra_ref; fp; fp = nextfp) {
902505c0 715 nextfp = fp->f_filef;
88a7a62a
SL
716 if (fp->f_count == 0)
717 continue;
cb9bf523
KM
718 if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
719 *fpp++ = fp;
720 nunref++;
721 fp->f_count++;
722 }
88a7a62a 723 }
cb9bf523
KM
724 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
725 sorflush((struct socket *)(*fpp)->f_data);
726 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
727 closef(*fpp);
728 free((caddr_t)extra_ref, M_FILE);
88a7a62a
SL
729 unp_gcing = 0;
730}
731
261a8548
MK
732unp_dispose(m)
733 struct mbuf *m;
734{
735 int unp_discard();
736
148703ec
MK
737 if (m)
738 unp_scan(m, unp_discard);
261a8548
MK
739}
740
741unp_scan(m0, op)
742 register struct mbuf *m0;
88a7a62a
SL
743 int (*op)();
744{
261a8548 745 register struct mbuf *m;
88a7a62a 746 register struct file **rp;
d83a7d17 747 register struct cmsghdr *cm;
88a7a62a 748 register int i;
148703ec 749 int qfds;
261a8548
MK
750
751 while (m0) {
752 for (m = m0; m; m = m->m_next)
d83a7d17
MK
753 if (m->m_type == MT_CONTROL &&
754 m->m_len >= sizeof(*cm)) {
0293c204 755 cm = mtod(m, struct cmsghdr *);
d83a7d17
MK
756 if (cm->cmsg_level != SOL_SOCKET ||
757 cm->cmsg_type != SCM_RIGHTS)
758 continue;
0293c204
KS
759 qfds = (cm->cmsg_len - sizeof *cm)
760 / sizeof (struct file *);
761 rp = (struct file **)(cm + 1);
261a8548
MK
762 for (i = 0; i < qfds; i++)
763 (*op)(*rp++);
764 break; /* XXX, but saves time */
765 }
148703ec 766 m0 = m0->m_act;
88a7a62a 767 }
88a7a62a
SL
768}
769
770unp_mark(fp)
771 struct file *fp;
772{
773
774 if (fp->f_flag & FMARK)
775 return;
776 unp_defer++;
777 fp->f_flag |= (FMARK|FDEFER);
778}
779
780unp_discard(fp)
781 struct file *fp;
782{
783
784 fp->f_msgcount--;
6c0894dd 785 unp_rights--;
84096e8e 786 (void) closef(fp, (struct proc *)NULL);
88a7a62a 787}