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