Commit | Line | Data |
---|---|---|
da7c5cc6 KM |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
7068721c | 6 | * @(#)uipc_usrreq.c 6.15 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
d6213d15 | 8 | |
94368568 JB |
9 | #include "param.h" |
10 | #include "dir.h" | |
11 | #include "user.h" | |
12 | #include "mbuf.h" | |
13 | #include "domain.h" | |
14 | #include "protosw.h" | |
15 | #include "socket.h" | |
16 | #include "socketvar.h" | |
17 | #include "unpcb.h" | |
18 | #include "un.h" | |
19 | #include "inode.h" | |
20 | #include "file.h" | |
21 | #include "stat.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 | */ |
8ecea7bc | 31 | struct sockaddr sun_noname = { AF_UNIX }; |
0abd16a9 | 32 | ino_t unp_ino; /* fake inode numbers */ |
d6213d15 BJ |
33 | |
34 | /*ARGSUSED*/ | |
88a7a62a | 35 | uipc_usrreq(so, req, m, nam, rights) |
d6213d15 BJ |
36 | struct socket *so; |
37 | int req; | |
88a7a62a | 38 | struct mbuf *m, *nam, *rights; |
d6213d15 BJ |
39 | { |
40 | struct unpcb *unp = sotounpcb(so); | |
41 | register struct socket *so2; | |
42 | int error = 0; | |
43 | ||
88a7a62a SL |
44 | if (req != PRU_SEND && rights && rights->m_len) { |
45 | error = EOPNOTSUPP; | |
46 | goto release; | |
47 | } | |
48 | if (unp == 0 && req != PRU_ATTACH) { | |
49 | error = EINVAL; | |
50 | goto release; | |
51 | } | |
d6213d15 BJ |
52 | switch (req) { |
53 | ||
54 | case PRU_ATTACH: | |
55 | if (unp) { | |
4f083fd7 | 56 | error = EISCONN; |
d6213d15 BJ |
57 | break; |
58 | } | |
fca5570f | 59 | error = unp_attach(so); |
d6213d15 BJ |
60 | break; |
61 | ||
62 | case PRU_DETACH: | |
63 | unp_detach(unp); | |
64 | break; | |
65 | ||
4f083fd7 SL |
66 | case PRU_BIND: |
67 | error = unp_bind(unp, nam); | |
68 | break; | |
69 | ||
70 | case PRU_LISTEN: | |
71 | if (unp->unp_inode == 0) | |
72 | error = EINVAL; | |
73 | break; | |
74 | ||
d6213d15 | 75 | case PRU_CONNECT: |
fca5570f | 76 | error = unp_connect(so, nam); |
d6213d15 BJ |
77 | break; |
78 | ||
88a7a62a | 79 | case PRU_CONNECT2: |
5a48956d SL |
80 | error = unp_connect2(so, (struct mbuf *)0, |
81 | (struct socket *)nam); | |
88a7a62a SL |
82 | break; |
83 | ||
d6213d15 BJ |
84 | case PRU_DISCONNECT: |
85 | unp_disconnect(unp); | |
86 | break; | |
87 | ||
4f083fd7 SL |
88 | case PRU_ACCEPT: |
89 | nam->m_len = unp->unp_remaddr->m_len; | |
90 | bcopy(mtod(unp->unp_remaddr, caddr_t), | |
91 | mtod(nam, caddr_t), (unsigned)nam->m_len); | |
d6213d15 BJ |
92 | break; |
93 | ||
94 | case PRU_SHUTDOWN: | |
95 | socantsendmore(so); | |
96 | unp_usrclosed(unp); | |
97 | break; | |
d6213d15 BJ |
98 | |
99 | case PRU_RCVD: | |
100 | switch (so->so_type) { | |
101 | ||
102 | case SOCK_DGRAM: | |
103 | panic("uipc 1"); | |
5fe6f9d1 | 104 | /*NOTREACHED*/ |
d6213d15 | 105 | |
5fe6f9d1 | 106 | case SOCK_STREAM: |
d6213d15 BJ |
107 | #define rcv (&so->so_rcv) |
108 | #define snd (&so2->so_snd) | |
109 | if (unp->unp_conn == 0) | |
110 | break; | |
111 | so2 = unp->unp_conn->unp_socket; | |
112 | /* | |
113 | * Transfer resources back to send port | |
114 | * and wakeup any waiting to write. | |
115 | */ | |
116 | snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; | |
117 | rcv->sb_mbmax = rcv->sb_mbcnt; | |
118 | snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; | |
119 | rcv->sb_hiwat = rcv->sb_cc; | |
9c40f33e | 120 | sowwakeup(so2); |
d6213d15 BJ |
121 | #undef snd |
122 | #undef rcv | |
d6213d15 BJ |
123 | break; |
124 | ||
125 | default: | |
126 | panic("uipc 2"); | |
127 | } | |
128 | break; | |
129 | ||
130 | case PRU_SEND: | |
131 | switch (so->so_type) { | |
132 | ||
133 | case SOCK_DGRAM: | |
fca5570f | 134 | if (nam) { |
d6213d15 BJ |
135 | if (unp->unp_conn) { |
136 | error = EISCONN; | |
137 | break; | |
138 | } | |
fca5570f | 139 | error = unp_connect(so, nam); |
d6213d15 BJ |
140 | if (error) |
141 | break; | |
142 | } else { | |
143 | if (unp->unp_conn == 0) { | |
144 | error = ENOTCONN; | |
145 | break; | |
146 | } | |
147 | } | |
148 | so2 = unp->unp_conn->unp_socket; | |
4f083fd7 | 149 | /* BEGIN XXX */ |
88a7a62a SL |
150 | if (rights) { |
151 | error = unp_internalize(rights); | |
152 | if (error) | |
153 | break; | |
154 | } | |
155 | if (sbspace(&so2->so_rcv) > 0) { | |
8ecea7bc SL |
156 | /* |
157 | * There's no record of source socket's | |
158 | * name, so send null name for the moment. | |
159 | */ | |
9c40f33e MK |
160 | if (sbappendaddr(&so2->so_rcv, |
161 | &sun_noname, m, rights)) { | |
162 | sorwakeup(so2); | |
163 | m = 0; | |
7068721c MK |
164 | } else |
165 | error = ENOBUFS; | |
88a7a62a | 166 | } |
4f083fd7 | 167 | /* END XXX */ |
fca5570f | 168 | if (nam) |
4f083fd7 | 169 | unp_disconnect(unp); |
d6213d15 BJ |
170 | break; |
171 | ||
172 | case SOCK_STREAM: | |
173 | #define rcv (&so2->so_rcv) | |
174 | #define snd (&so->so_snd) | |
88a7a62a SL |
175 | if (rights && rights->m_len) { |
176 | error = EOPNOTSUPP; | |
177 | break; | |
178 | } | |
7068721c MK |
179 | if (so->so_state & SS_CANTSENDMORE) { |
180 | error = EPIPE; | |
181 | break; | |
182 | } | |
d6213d15 BJ |
183 | if (unp->unp_conn == 0) |
184 | panic("uipc 3"); | |
185 | so2 = unp->unp_conn->unp_socket; | |
186 | /* | |
187 | * Send to paired receive port, and then | |
188 | * give it enough resources to hold what it already has. | |
189 | * Wake up readers. | |
190 | */ | |
191 | sbappend(rcv, m); | |
192 | snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; | |
193 | rcv->sb_mbmax = rcv->sb_mbcnt; | |
194 | snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; | |
195 | rcv->sb_hiwat = rcv->sb_cc; | |
9c40f33e MK |
196 | sorwakeup(so2); |
197 | m = 0; | |
d6213d15 BJ |
198 | #undef snd |
199 | #undef rcv | |
200 | break; | |
201 | ||
202 | default: | |
203 | panic("uipc 4"); | |
204 | } | |
205 | break; | |
206 | ||
207 | case PRU_ABORT: | |
208 | unp_drop(unp, ECONNABORTED); | |
209 | break; | |
210 | ||
211 | /* SOME AS YET UNIMPLEMENTED HOOKS */ | |
212 | case PRU_CONTROL: | |
1116b929 | 213 | return (EOPNOTSUPP); |
d6213d15 | 214 | |
d6213d15 | 215 | /* END UNIMPLEMENTED HOOKS */ |
bfd4e82c MK |
216 | case PRU_SENSE: |
217 | ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; | |
218 | if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { | |
219 | so2 = unp->unp_conn->unp_socket; | |
220 | ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; | |
221 | } | |
0abd16a9 MK |
222 | ((struct stat *) m)->st_dev = NODEV; |
223 | ((struct stat *) m)->st_ino = unp_ino++; | |
bfd4e82c | 224 | return (0); |
d6213d15 BJ |
225 | |
226 | case PRU_RCVOOB: | |
913b2f19 | 227 | return (EOPNOTSUPP); |
d6213d15 BJ |
228 | |
229 | case PRU_SENDOOB: | |
9c40f33e | 230 | error = EOPNOTSUPP; |
d6213d15 BJ |
231 | break; |
232 | ||
233 | case PRU_SOCKADDR: | |
234 | break; | |
235 | ||
a7343092 SL |
236 | case PRU_PEERADDR: |
237 | break; | |
238 | ||
d6213d15 BJ |
239 | case PRU_SLOWTIMO: |
240 | break; | |
241 | ||
242 | default: | |
243 | panic("piusrreq"); | |
244 | } | |
88a7a62a SL |
245 | release: |
246 | if (m) | |
247 | m_freem(m); | |
e14b8185 | 248 | return (error); |
d6213d15 BJ |
249 | } |
250 | ||
bfd4e82c MK |
251 | /* |
252 | * We assign all buffering for stream sockets to the source, | |
253 | * as that is where the flow control is implemented. | |
254 | * Datagram sockets really use the sendspace as the maximum datagram size, | |
255 | * and don't really want to reserve the sendspace. Their recvspace should | |
256 | * be large enough for at least one max-size datagram plus address. | |
257 | */ | |
258 | #define PIPSIZ 4096 | |
259 | int unpst_sendspace = PIPSIZ; | |
260 | int unpst_recvspace = 0; | |
261 | int unpdg_sendspace = 2*1024; /* really max datagram size */ | |
262 | int unpdg_recvspace = 4*1024; | |
d6213d15 | 263 | |
4f083fd7 | 264 | unp_attach(so) |
d6213d15 | 265 | struct socket *so; |
d6213d15 | 266 | { |
4f083fd7 | 267 | register struct mbuf *m; |
d6213d15 | 268 | register struct unpcb *unp; |
d6213d15 BJ |
269 | int error; |
270 | ||
bfd4e82c MK |
271 | switch (so->so_type) { |
272 | ||
273 | case SOCK_STREAM: | |
274 | error = soreserve(so, unpst_sendspace, unpst_recvspace); | |
275 | break; | |
276 | ||
277 | case SOCK_DGRAM: | |
278 | error = soreserve(so, unpdg_sendspace, unpdg_recvspace); | |
279 | break; | |
280 | } | |
d6213d15 | 281 | if (error) |
5fe6f9d1 | 282 | return (error); |
cce93e4b | 283 | m = m_getclr(M_DONTWAIT, MT_PCB); |
5fe6f9d1 SL |
284 | if (m == NULL) |
285 | return (ENOBUFS); | |
d6213d15 BJ |
286 | unp = mtod(m, struct unpcb *); |
287 | so->so_pcb = (caddr_t)unp; | |
288 | unp->unp_socket = so; | |
d6213d15 | 289 | return (0); |
d6213d15 BJ |
290 | } |
291 | ||
d6213d15 | 292 | unp_detach(unp) |
4f083fd7 | 293 | register struct unpcb *unp; |
d6213d15 BJ |
294 | { |
295 | ||
296 | if (unp->unp_inode) { | |
148703ec | 297 | unp->unp_inode->i_socket = 0; |
d6213d15 BJ |
298 | irele(unp->unp_inode); |
299 | unp->unp_inode = 0; | |
300 | } | |
301 | if (unp->unp_conn) | |
302 | unp_disconnect(unp); | |
303 | while (unp->unp_refs) | |
304 | unp_drop(unp->unp_refs, ECONNRESET); | |
305 | soisdisconnected(unp->unp_socket); | |
306 | unp->unp_socket->so_pcb = 0; | |
4f083fd7 SL |
307 | m_freem(unp->unp_remaddr); |
308 | (void) m_free(dtom(unp)); | |
d6213d15 BJ |
309 | } |
310 | ||
4f083fd7 | 311 | unp_bind(unp, nam) |
d6213d15 | 312 | struct unpcb *unp; |
4f083fd7 | 313 | struct mbuf *nam; |
d6213d15 | 314 | { |
4f083fd7 | 315 | struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
d6213d15 | 316 | register struct inode *ip; |
715baff1 | 317 | register struct nameidata *ndp = &u.u_nd; |
4f083fd7 | 318 | int error; |
d6213d15 | 319 | |
715baff1 | 320 | ndp->ni_dirp = soun->sun_path; |
88a7a62a SL |
321 | if (nam->m_len == MLEN) |
322 | return (EINVAL); | |
323 | *(mtod(nam, caddr_t) + nam->m_len) = 0; | |
324 | /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ | |
715baff1 KM |
325 | ndp->ni_nameiop = CREATE | FOLLOW; |
326 | ndp->ni_segflg = UIO_SYSSPACE; | |
327 | ip = namei(ndp); | |
d6213d15 BJ |
328 | if (ip) { |
329 | iput(ip); | |
5fe6f9d1 | 330 | return (EADDRINUSE); |
d6213d15 | 331 | } |
f3bb1ae7 SL |
332 | if (error = u.u_error) { |
333 | u.u_error = 0; /* XXX */ | |
334 | return (error); | |
335 | } | |
715baff1 | 336 | ip = maknode(IFSOCK | 0777, ndp); |
d6213d15 BJ |
337 | if (ip == NULL) { |
338 | error = u.u_error; /* XXX */ | |
339 | u.u_error = 0; /* XXX */ | |
340 | return (error); | |
341 | } | |
342 | ip->i_socket = unp->unp_socket; | |
343 | unp->unp_inode = ip; | |
344 | iunlock(ip); /* but keep reference */ | |
345 | return (0); | |
346 | } | |
347 | ||
4f083fd7 | 348 | unp_connect(so, nam) |
d6213d15 | 349 | struct socket *so; |
4f083fd7 | 350 | struct mbuf *nam; |
d6213d15 | 351 | { |
4f083fd7 | 352 | register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
4f083fd7 | 353 | register struct inode *ip; |
d6213d15 | 354 | int error; |
88a7a62a | 355 | register struct socket *so2; |
715baff1 | 356 | register struct nameidata *ndp = &u.u_nd; |
d6213d15 | 357 | |
715baff1 | 358 | ndp->ni_dirp = soun->sun_path; |
88a7a62a SL |
359 | if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) |
360 | return (EMSGSIZE); | |
361 | *(mtod(nam, caddr_t) + nam->m_len) = 0; | |
715baff1 KM |
362 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
363 | ndp->ni_segflg = UIO_SYSSPACE; | |
364 | ip = namei(ndp); | |
d6213d15 BJ |
365 | if (ip == 0) { |
366 | error = u.u_error; | |
367 | u.u_error = 0; | |
5fe6f9d1 | 368 | return (error); /* XXX */ |
d6213d15 | 369 | } |
9c40f33e MK |
370 | if (access(ip, IWRITE)) { |
371 | error = u.u_error; | |
372 | u.u_error = 0; /* XXX */ | |
373 | goto bad; | |
374 | } | |
d6213d15 BJ |
375 | if ((ip->i_mode&IFMT) != IFSOCK) { |
376 | error = ENOTSOCK; | |
377 | goto bad; | |
378 | } | |
379 | so2 = ip->i_socket; | |
380 | if (so2 == 0) { | |
381 | error = ECONNREFUSED; | |
382 | goto bad; | |
383 | } | |
5a48956d SL |
384 | if (so->so_type != so2->so_type) { |
385 | error = EPROTOTYPE; | |
386 | goto bad; | |
387 | } | |
388 | if (so->so_proto->pr_flags & PR_CONNREQUIRED && | |
389 | ((so2->so_options&SO_ACCEPTCONN) == 0 || | |
390 | (so2 = sonewconn(so2)) == 0)) { | |
391 | error = ECONNREFUSED; | |
392 | goto bad; | |
393 | } | |
88a7a62a SL |
394 | error = unp_connect2(so, nam, so2); |
395 | bad: | |
396 | iput(ip); | |
397 | return (error); | |
398 | } | |
399 | ||
400 | unp_connect2(so, sonam, so2) | |
401 | register struct socket *so; | |
402 | struct mbuf *sonam; | |
403 | register struct socket *so2; | |
404 | { | |
405 | register struct unpcb *unp = sotounpcb(so); | |
406 | register struct unpcb *unp2; | |
407 | ||
408 | if (so2->so_type != so->so_type) | |
409 | return (EPROTOTYPE); | |
ccffacbd SL |
410 | unp2 = sotounpcb(so2); |
411 | unp->unp_conn = unp2; | |
d6213d15 BJ |
412 | switch (so->so_type) { |
413 | ||
414 | case SOCK_DGRAM: | |
d6213d15 BJ |
415 | unp->unp_nextref = unp2->unp_refs; |
416 | unp2->unp_refs = unp; | |
9c40f33e | 417 | soisconnected(so); |
d6213d15 BJ |
418 | break; |
419 | ||
420 | case SOCK_STREAM: | |
4f083fd7 | 421 | unp2->unp_conn = unp; |
88a7a62a SL |
422 | if (sonam) |
423 | unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); | |
ccffacbd SL |
424 | soisconnected(so2); |
425 | soisconnected(so); | |
d6213d15 BJ |
426 | break; |
427 | ||
428 | default: | |
88a7a62a | 429 | panic("unp_connect2"); |
d6213d15 | 430 | } |
d6213d15 | 431 | return (0); |
d6213d15 | 432 | } |
4f083fd7 SL |
433 | |
434 | unp_disconnect(unp) | |
435 | struct unpcb *unp; | |
436 | { | |
437 | register struct unpcb *unp2 = unp->unp_conn; | |
438 | ||
439 | if (unp2 == 0) | |
440 | return; | |
441 | unp->unp_conn = 0; | |
4f083fd7 SL |
442 | switch (unp->unp_socket->so_type) { |
443 | ||
444 | case SOCK_DGRAM: | |
445 | if (unp2->unp_refs == unp) | |
446 | unp2->unp_refs = unp->unp_nextref; | |
447 | else { | |
448 | unp2 = unp2->unp_refs; | |
449 | for (;;) { | |
450 | if (unp2 == 0) | |
451 | panic("unp_disconnect"); | |
452 | if (unp2->unp_nextref == unp) | |
453 | break; | |
454 | unp2 = unp2->unp_nextref; | |
455 | } | |
456 | unp2->unp_nextref = unp->unp_nextref; | |
457 | } | |
458 | unp->unp_nextref = 0; | |
c5935bca | 459 | unp->unp_socket->so_state &= ~SS_ISCONNECTED; |
4f083fd7 SL |
460 | break; |
461 | ||
462 | case SOCK_STREAM: | |
ccffacbd | 463 | soisdisconnected(unp->unp_socket); |
4f083fd7 SL |
464 | unp2->unp_conn = 0; |
465 | soisdisconnected(unp2->unp_socket); | |
4f083fd7 SL |
466 | break; |
467 | } | |
468 | } | |
469 | ||
88a7a62a | 470 | #ifdef notdef |
4f083fd7 SL |
471 | unp_abort(unp) |
472 | struct unpcb *unp; | |
473 | { | |
474 | ||
475 | unp_detach(unp); | |
476 | } | |
88a7a62a | 477 | #endif |
4f083fd7 SL |
478 | |
479 | /*ARGSUSED*/ | |
480 | unp_usrclosed(unp) | |
481 | struct unpcb *unp; | |
482 | { | |
483 | ||
484 | } | |
485 | ||
486 | unp_drop(unp, errno) | |
487 | struct unpcb *unp; | |
488 | int errno; | |
489 | { | |
d12671e0 | 490 | struct socket *so = unp->unp_socket; |
4f083fd7 | 491 | |
d12671e0 | 492 | so->so_error = errno; |
4f083fd7 | 493 | unp_disconnect(unp); |
d12671e0 MK |
494 | if (so->so_head) { |
495 | so->so_pcb = (caddr_t) 0; | |
cd9b8206 | 496 | m_freem(unp->unp_remaddr); |
d12671e0 MK |
497 | (void) m_free(dtom(unp)); |
498 | sofree(so); | |
499 | } | |
4f083fd7 SL |
500 | } |
501 | ||
88a7a62a | 502 | #ifdef notdef |
4f083fd7 SL |
503 | unp_drain() |
504 | { | |
505 | ||
506 | } | |
88a7a62a SL |
507 | #endif |
508 | ||
509 | unp_externalize(rights) | |
510 | struct mbuf *rights; | |
511 | { | |
512 | int newfds = rights->m_len / sizeof (int); | |
513 | register int i; | |
514 | register struct file **rp = mtod(rights, struct file **); | |
515 | register struct file *fp; | |
516 | int f; | |
517 | ||
518 | if (newfds > ufavail()) { | |
519 | for (i = 0; i < newfds; i++) { | |
520 | fp = *rp; | |
521 | unp_discard(fp); | |
522 | *rp++ = 0; | |
523 | } | |
524 | return (EMSGSIZE); | |
525 | } | |
526 | for (i = 0; i < newfds; i++) { | |
527 | f = ufalloc(0); | |
528 | if (f < 0) | |
529 | panic("unp_externalize"); | |
530 | fp = *rp; | |
531 | u.u_ofile[f] = fp; | |
532 | fp->f_msgcount--; | |
bb3b4851 | 533 | *(int *)rp++ = f; |
88a7a62a SL |
534 | } |
535 | return (0); | |
536 | } | |
537 | ||
538 | unp_internalize(rights) | |
539 | struct mbuf *rights; | |
540 | { | |
541 | register struct file **rp; | |
542 | int oldfds = rights->m_len / sizeof (int); | |
543 | register int i; | |
544 | register struct file *fp; | |
545 | ||
546 | rp = mtod(rights, struct file **); | |
44eb2da3 | 547 | for (i = 0; i < oldfds; i++) |
88a7a62a SL |
548 | if (getf(*(int *)rp++) == 0) |
549 | return (EBADF); | |
550 | rp = mtod(rights, struct file **); | |
44eb2da3 | 551 | for (i = 0; i < oldfds; i++) { |
88a7a62a SL |
552 | fp = getf(*(int *)rp); |
553 | *rp++ = fp; | |
554 | fp->f_count++; | |
555 | fp->f_msgcount++; | |
556 | } | |
557 | return (0); | |
558 | } | |
559 | ||
560 | int unp_defer, unp_gcing; | |
561 | int unp_mark(); | |
261a8548 | 562 | extern struct domain unixdomain; |
88a7a62a SL |
563 | |
564 | unp_gc() | |
565 | { | |
566 | register struct file *fp; | |
567 | register struct socket *so; | |
568 | ||
569 | if (unp_gcing) | |
570 | return; | |
571 | unp_gcing = 1; | |
572 | restart: | |
573 | unp_defer = 0; | |
574 | for (fp = file; fp < fileNFILE; fp++) | |
575 | fp->f_flag &= ~(FMARK|FDEFER); | |
576 | do { | |
577 | for (fp = file; fp < fileNFILE; fp++) { | |
578 | if (fp->f_count == 0) | |
579 | continue; | |
580 | if (fp->f_flag & FDEFER) { | |
581 | fp->f_flag &= ~FDEFER; | |
582 | unp_defer--; | |
583 | } else { | |
584 | if (fp->f_flag & FMARK) | |
585 | continue; | |
586 | if (fp->f_count == fp->f_msgcount) | |
587 | continue; | |
588 | fp->f_flag |= FMARK; | |
589 | } | |
590 | if (fp->f_type != DTYPE_SOCKET) | |
591 | continue; | |
592 | so = (struct socket *)fp->f_data; | |
261a8548 | 593 | if (so->so_proto->pr_domain != &unixdomain || |
c5935bca | 594 | (so->so_proto->pr_flags&PR_RIGHTS) == 0) |
88a7a62a SL |
595 | continue; |
596 | if (so->so_rcv.sb_flags & SB_LOCK) { | |
597 | sbwait(&so->so_rcv); | |
598 | goto restart; | |
599 | } | |
600 | unp_scan(so->so_rcv.sb_mb, unp_mark); | |
601 | } | |
602 | } while (unp_defer); | |
603 | for (fp = file; fp < fileNFILE; fp++) { | |
604 | if (fp->f_count == 0) | |
605 | continue; | |
606 | if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { | |
607 | if (fp->f_type != DTYPE_SOCKET) | |
608 | panic("unp_gc"); | |
609 | (void) soshutdown((struct socket *)fp->f_data, 0); | |
610 | } | |
611 | } | |
612 | unp_gcing = 0; | |
613 | } | |
614 | ||
261a8548 MK |
615 | unp_dispose(m) |
616 | struct mbuf *m; | |
617 | { | |
618 | int unp_discard(); | |
619 | ||
148703ec MK |
620 | if (m) |
621 | unp_scan(m, unp_discard); | |
261a8548 MK |
622 | } |
623 | ||
624 | unp_scan(m0, op) | |
625 | register struct mbuf *m0; | |
88a7a62a SL |
626 | int (*op)(); |
627 | { | |
261a8548 | 628 | register struct mbuf *m; |
88a7a62a SL |
629 | register struct file **rp; |
630 | register int i; | |
148703ec | 631 | int qfds; |
261a8548 MK |
632 | |
633 | while (m0) { | |
634 | for (m = m0; m; m = m->m_next) | |
635 | if (m->m_type == MT_RIGHTS && m->m_len) { | |
636 | qfds = m->m_len / sizeof (struct file *); | |
637 | rp = mtod(m, struct file **); | |
638 | for (i = 0; i < qfds; i++) | |
639 | (*op)(*rp++); | |
640 | break; /* XXX, but saves time */ | |
641 | } | |
148703ec | 642 | m0 = m0->m_act; |
88a7a62a | 643 | } |
88a7a62a SL |
644 | } |
645 | ||
646 | unp_mark(fp) | |
647 | struct file *fp; | |
648 | { | |
649 | ||
650 | if (fp->f_flag & FMARK) | |
651 | return; | |
652 | unp_defer++; | |
653 | fp->f_flag |= (FMARK|FDEFER); | |
654 | } | |
655 | ||
656 | unp_discard(fp) | |
657 | struct file *fp; | |
658 | { | |
659 | ||
660 | fp->f_msgcount--; | |
44eb2da3 | 661 | closef(fp); |
88a7a62a | 662 | } |