date and time created 85/07/31 17:07:57 by sam
[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 *
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 31struct sockaddr sun_noname = { AF_UNIX };
0abd16a9 32ino_t unp_ino; /* 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
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
245release:
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
259int unpst_sendspace = PIPSIZ;
260int unpst_recvspace = 0;
261int unpdg_sendspace = 2*1024; /* really max datagram size */
262int unpdg_recvspace = 4*1024;
d6213d15 263
4f083fd7 264unp_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 292unp_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 311unp_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 348unp_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);
395bad:
396 iput(ip);
397 return (error);
398}
399
400unp_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
434unp_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
471unp_abort(unp)
472 struct unpcb *unp;
473{
474
475 unp_detach(unp);
476}
88a7a62a 477#endif
4f083fd7
SL
478
479/*ARGSUSED*/
480unp_usrclosed(unp)
481 struct unpcb *unp;
482{
483
484}
485
486unp_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
503unp_drain()
504{
505
506}
88a7a62a
SL
507#endif
508
509unp_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
538unp_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
560int unp_defer, unp_gcing;
561int unp_mark();
261a8548 562extern struct domain unixdomain;
88a7a62a
SL
563
564unp_gc()
565{
566 register struct file *fp;
567 register struct socket *so;
568
569 if (unp_gcing)
570 return;
571 unp_gcing = 1;
572restart:
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
615unp_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
624unp_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
646unp_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
656unp_discard(fp)
657 struct file *fp;
658{
659
660 fp->f_msgcount--;
44eb2da3 661 closef(fp);
88a7a62a 662}