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