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