fix key letter so ^A, ^B, etc. isn't generated.
[unix-history] / usr / src / sys / kern / uipc_usrreq.c
CommitLineData
bb3b4851 1/* uipc_usrreq.c 6.2 83/09/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"
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
a7343092
SL
215 case PRU_PEERADDR:
216 break;
217
d6213d15
BJ
218 case PRU_SLOWTIMO:
219 break;
220
221 default:
222 panic("piusrreq");
223 }
88a7a62a
SL
224release:
225 if (m)
226 m_freem(m);
e14b8185 227 return (error);
d6213d15
BJ
228}
229
88a7a62a 230/* SHOULD BE PIPSIZ and 0 */
d6213d15
BJ
231int unp_sendspace = 1024*2;
232int unp_recvspace = 1024*2;
233
4f083fd7 234unp_attach(so)
d6213d15 235 struct socket *so;
d6213d15 236{
4f083fd7 237 register struct mbuf *m;
d6213d15 238 register struct unpcb *unp;
d6213d15
BJ
239 int error;
240
241 error = soreserve(so, unp_sendspace, unp_recvspace);
242 if (error)
5fe6f9d1 243 return (error);
cce93e4b 244 m = m_getclr(M_DONTWAIT, MT_PCB);
5fe6f9d1
SL
245 if (m == NULL)
246 return (ENOBUFS);
d6213d15
BJ
247 unp = mtod(m, struct unpcb *);
248 so->so_pcb = (caddr_t)unp;
249 unp->unp_socket = so;
d6213d15 250 return (0);
d6213d15
BJ
251}
252
d6213d15 253unp_detach(unp)
4f083fd7 254 register struct unpcb *unp;
d6213d15
BJ
255{
256
257 if (unp->unp_inode) {
258 irele(unp->unp_inode);
259 unp->unp_inode = 0;
260 }
261 if (unp->unp_conn)
262 unp_disconnect(unp);
263 while (unp->unp_refs)
264 unp_drop(unp->unp_refs, ECONNRESET);
265 soisdisconnected(unp->unp_socket);
266 unp->unp_socket->so_pcb = 0;
4f083fd7
SL
267 m_freem(unp->unp_remaddr);
268 (void) m_free(dtom(unp));
d6213d15
BJ
269}
270
4f083fd7 271unp_bind(unp, nam)
d6213d15 272 struct unpcb *unp;
4f083fd7 273 struct mbuf *nam;
d6213d15 274{
4f083fd7 275 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
d6213d15 276 register struct inode *ip;
d6213d15 277 extern schar();
4f083fd7 278 int error;
d6213d15
BJ
279
280 u.u_dirp = soun->sun_path;
88a7a62a
SL
281 if (nam->m_len == MLEN)
282 return (EINVAL);
283 *(mtod(nam, caddr_t) + nam->m_len) = 0;
284/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
4f083fd7 285 ip = namei(schar, CREATE, 1);
d6213d15
BJ
286 if (ip) {
287 iput(ip);
5fe6f9d1 288 return (EADDRINUSE);
d6213d15 289 }
f3bb1ae7
SL
290 if (error = u.u_error) {
291 u.u_error = 0; /* XXX */
292 return (error);
293 }
d6213d15
BJ
294 ip = maknode(IFSOCK | 0777);
295 if (ip == NULL) {
296 error = u.u_error; /* XXX */
297 u.u_error = 0; /* XXX */
298 return (error);
299 }
300 ip->i_socket = unp->unp_socket;
301 unp->unp_inode = ip;
302 iunlock(ip); /* but keep reference */
303 return (0);
304}
305
4f083fd7 306unp_connect(so, nam)
d6213d15 307 struct socket *so;
4f083fd7 308 struct mbuf *nam;
d6213d15 309{
4f083fd7 310 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
4f083fd7 311 register struct inode *ip;
d6213d15 312 int error;
88a7a62a 313 register struct socket *so2;
d6213d15
BJ
314
315 u.u_dirp = soun->sun_path;
88a7a62a
SL
316 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
317 return (EMSGSIZE);
318 *(mtod(nam, caddr_t) + nam->m_len) = 0;
4f083fd7 319 ip = namei(schar, LOOKUP, 1);
d6213d15
BJ
320 if (ip == 0) {
321 error = u.u_error;
322 u.u_error = 0;
5fe6f9d1 323 return (error); /* XXX */
d6213d15 324 }
d6213d15
BJ
325 if ((ip->i_mode&IFMT) != IFSOCK) {
326 error = ENOTSOCK;
327 goto bad;
328 }
329 so2 = ip->i_socket;
330 if (so2 == 0) {
331 error = ECONNREFUSED;
332 goto bad;
333 }
5a48956d
SL
334 if (so->so_type != so2->so_type) {
335 error = EPROTOTYPE;
336 goto bad;
337 }
338 if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
339 ((so2->so_options&SO_ACCEPTCONN) == 0 ||
340 (so2 = sonewconn(so2)) == 0)) {
341 error = ECONNREFUSED;
342 goto bad;
343 }
88a7a62a
SL
344 error = unp_connect2(so, nam, so2);
345bad:
346 iput(ip);
347 return (error);
348}
349
350unp_connect2(so, sonam, so2)
351 register struct socket *so;
352 struct mbuf *sonam;
353 register struct socket *so2;
354{
355 register struct unpcb *unp = sotounpcb(so);
356 register struct unpcb *unp2;
357
358 if (so2->so_type != so->so_type)
359 return (EPROTOTYPE);
ccffacbd
SL
360 unp2 = sotounpcb(so2);
361 unp->unp_conn = unp2;
d6213d15
BJ
362 switch (so->so_type) {
363
364 case SOCK_DGRAM:
d6213d15
BJ
365 unp->unp_nextref = unp2->unp_refs;
366 unp2->unp_refs = unp;
367 break;
368
369 case SOCK_STREAM:
4f083fd7 370 unp2->unp_conn = unp;
88a7a62a
SL
371 if (sonam)
372 unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
ccffacbd
SL
373 soisconnected(so2);
374 soisconnected(so);
d6213d15
BJ
375 break;
376
377 default:
88a7a62a 378 panic("unp_connect2");
d6213d15 379 }
d6213d15 380 return (0);
d6213d15 381}
4f083fd7
SL
382
383unp_disconnect(unp)
384 struct unpcb *unp;
385{
386 register struct unpcb *unp2 = unp->unp_conn;
387
388 if (unp2 == 0)
389 return;
390 unp->unp_conn = 0;
4f083fd7
SL
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:
ccffacbd 411 soisdisconnected(unp->unp_socket);
4f083fd7
SL
412 unp2->unp_conn = 0;
413 soisdisconnected(unp2->unp_socket);
4f083fd7
SL
414 break;
415 }
416}
417
88a7a62a 418#ifdef notdef
4f083fd7
SL
419unp_abort(unp)
420 struct unpcb *unp;
421{
422
423 unp_detach(unp);
424}
88a7a62a 425#endif
4f083fd7
SL
426
427/*ARGSUSED*/
428unp_usrclosed(unp)
429 struct unpcb *unp;
430{
431
432}
433
434unp_drop(unp, errno)
435 struct unpcb *unp;
436 int errno;
437{
438
439 unp->unp_socket->so_error = errno;
440 unp_disconnect(unp);
441}
442
88a7a62a 443#ifdef notdef
4f083fd7
SL
444unp_drain()
445{
446
447}
88a7a62a
SL
448#endif
449
450unp_externalize(rights)
451 struct mbuf *rights;
452{
453 int newfds = rights->m_len / sizeof (int);
454 register int i;
455 register struct file **rp = mtod(rights, struct file **);
456 register struct file *fp;
457 int f;
458
459 if (newfds > ufavail()) {
460 for (i = 0; i < newfds; i++) {
461 fp = *rp;
462 unp_discard(fp);
463 *rp++ = 0;
464 }
465 return (EMSGSIZE);
466 }
467 for (i = 0; i < newfds; i++) {
468 f = ufalloc(0);
469 if (f < 0)
470 panic("unp_externalize");
471 fp = *rp;
472 u.u_ofile[f] = fp;
473 fp->f_msgcount--;
bb3b4851 474 *(int *)rp++ = f;
88a7a62a
SL
475 }
476 return (0);
477}
478
479unp_internalize(rights)
480 struct mbuf *rights;
481{
482 register struct file **rp;
483 int oldfds = rights->m_len / sizeof (int);
484 register int i;
485 register struct file *fp;
486
487 rp = mtod(rights, struct file **);
44eb2da3 488 for (i = 0; i < oldfds; i++)
88a7a62a
SL
489 if (getf(*(int *)rp++) == 0)
490 return (EBADF);
491 rp = mtod(rights, struct file **);
44eb2da3 492 for (i = 0; i < oldfds; i++) {
88a7a62a
SL
493 fp = getf(*(int *)rp);
494 *rp++ = fp;
495 fp->f_count++;
496 fp->f_msgcount++;
497 }
498 return (0);
499}
500
501int unp_defer, unp_gcing;
502int unp_mark();
503
504unp_gc()
505{
506 register struct file *fp;
507 register struct socket *so;
508
509 if (unp_gcing)
510 return;
511 unp_gcing = 1;
512restart:
513 unp_defer = 0;
514 for (fp = file; fp < fileNFILE; fp++)
515 fp->f_flag &= ~(FMARK|FDEFER);
516 do {
517 for (fp = file; fp < fileNFILE; fp++) {
518 if (fp->f_count == 0)
519 continue;
520 if (fp->f_flag & FDEFER) {
521 fp->f_flag &= ~FDEFER;
522 unp_defer--;
523 } else {
524 if (fp->f_flag & FMARK)
525 continue;
526 if (fp->f_count == fp->f_msgcount)
527 continue;
528 fp->f_flag |= FMARK;
529 }
530 if (fp->f_type != DTYPE_SOCKET)
531 continue;
532 so = (struct socket *)fp->f_data;
533 if (so->so_proto->pr_family != AF_UNIX ||
534 (so->so_proto->pr_flags&PR_ADDR) == 0)
535 continue;
536 if (so->so_rcv.sb_flags & SB_LOCK) {
537 sbwait(&so->so_rcv);
538 goto restart;
539 }
540 unp_scan(so->so_rcv.sb_mb, unp_mark);
541 }
542 } while (unp_defer);
543 for (fp = file; fp < fileNFILE; fp++) {
544 if (fp->f_count == 0)
545 continue;
546 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
547 if (fp->f_type != DTYPE_SOCKET)
548 panic("unp_gc");
549 (void) soshutdown((struct socket *)fp->f_data, 0);
550 }
551 }
552 unp_gcing = 0;
553}
554
555unp_scan(m, op)
556 register struct mbuf *m;
557 int (*op)();
558{
559 register struct file **rp;
560 register int i;
561 int qfds;
562
563 while (m) {
564 m = m->m_next;
565 if (m == 0)
566 goto bad;
567 if (m->m_len) {
568 qfds = m->m_len / sizeof (struct file *);
569 rp = mtod(m, struct file **);
570 for (i = 0; i < qfds; i++)
571 (*op)(*rp++);
572 }
573 do {
574 m = m->m_next;
575 if (m == 0)
576 goto bad;
577 } while (m->m_act == 0);
578 m = m->m_next;
579 }
580 return;
581bad:
582 panic("unp_gcscan");
583}
584
585unp_mark(fp)
586 struct file *fp;
587{
588
589 if (fp->f_flag & FMARK)
590 return;
591 unp_defer++;
592 fp->f_flag |= (FMARK|FDEFER);
593}
594
595unp_discard(fp)
596 struct file *fp;
597{
598
599 fp->f_msgcount--;
44eb2da3 600 closef(fp);
88a7a62a 601}