remove unused sonam arg to unp_connect2
[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 *
d97afdcc 6 * @(#)uipc_usrreq.c 6.20 (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
MK
197 if (rights)
198 sbappendrights(rcv, m, rights);
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
SL
243 case PRU_PEERADDR:
244 break;
245
d6213d15
BJ
246 case PRU_SLOWTIMO:
247 break;
248
249 default:
250 panic("piusrreq");
251 }
88a7a62a
SL
252release:
253 if (m)
254 m_freem(m);
e14b8185 255 return (error);
d6213d15
BJ
256}
257
bfd4e82c 258/*
6c0894dd
MK
259 * Both send and receive buffers are allocated PIPSIZ bytes of buffering
260 * for stream sockets, although the total for sender and receiver is
261 * actually only PIPSIZ.
bfd4e82c
MK
262 * Datagram sockets really use the sendspace as the maximum datagram size,
263 * and don't really want to reserve the sendspace. Their recvspace should
264 * be large enough for at least one max-size datagram plus address.
265 */
266#define PIPSIZ 4096
267int unpst_sendspace = PIPSIZ;
6c0894dd 268int unpst_recvspace = PIPSIZ;
bfd4e82c
MK
269int unpdg_sendspace = 2*1024; /* really max datagram size */
270int unpdg_recvspace = 4*1024;
d6213d15 271
6c0894dd
MK
272int unp_rights; /* file descriptors in flight */
273
4f083fd7 274unp_attach(so)
d6213d15 275 struct socket *so;
d6213d15 276{
4f083fd7 277 register struct mbuf *m;
d6213d15 278 register struct unpcb *unp;
d6213d15
BJ
279 int error;
280
bfd4e82c
MK
281 switch (so->so_type) {
282
283 case SOCK_STREAM:
284 error = soreserve(so, unpst_sendspace, unpst_recvspace);
285 break;
286
287 case SOCK_DGRAM:
288 error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
289 break;
290 }
d6213d15 291 if (error)
5fe6f9d1 292 return (error);
cce93e4b 293 m = m_getclr(M_DONTWAIT, MT_PCB);
5fe6f9d1
SL
294 if (m == NULL)
295 return (ENOBUFS);
d6213d15
BJ
296 unp = mtod(m, struct unpcb *);
297 so->so_pcb = (caddr_t)unp;
298 unp->unp_socket = so;
d6213d15 299 return (0);
d6213d15
BJ
300}
301
d6213d15 302unp_detach(unp)
4f083fd7 303 register struct unpcb *unp;
d6213d15
BJ
304{
305
306 if (unp->unp_inode) {
148703ec 307 unp->unp_inode->i_socket = 0;
d6213d15
BJ
308 irele(unp->unp_inode);
309 unp->unp_inode = 0;
310 }
311 if (unp->unp_conn)
312 unp_disconnect(unp);
313 while (unp->unp_refs)
314 unp_drop(unp->unp_refs, ECONNRESET);
315 soisdisconnected(unp->unp_socket);
316 unp->unp_socket->so_pcb = 0;
6c0894dd 317 m_freem(unp->unp_addr);
4f083fd7 318 (void) m_free(dtom(unp));
6c0894dd
MK
319 if (unp_rights)
320 unp_gc();
d6213d15
BJ
321}
322
4f083fd7 323unp_bind(unp, nam)
d6213d15 324 struct unpcb *unp;
4f083fd7 325 struct mbuf *nam;
d6213d15 326{
4f083fd7 327 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
d6213d15 328 register struct inode *ip;
715baff1 329 register struct nameidata *ndp = &u.u_nd;
4f083fd7 330 int error;
d6213d15 331
715baff1 332 ndp->ni_dirp = soun->sun_path;
9816c2d5 333 if (unp->unp_inode != NULL || nam->m_len == MLEN)
88a7a62a
SL
334 return (EINVAL);
335 *(mtod(nam, caddr_t) + nam->m_len) = 0;
336/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
715baff1
KM
337 ndp->ni_nameiop = CREATE | FOLLOW;
338 ndp->ni_segflg = UIO_SYSSPACE;
339 ip = namei(ndp);
d6213d15
BJ
340 if (ip) {
341 iput(ip);
5fe6f9d1 342 return (EADDRINUSE);
d6213d15 343 }
f3bb1ae7
SL
344 if (error = u.u_error) {
345 u.u_error = 0; /* XXX */
346 return (error);
347 }
715baff1 348 ip = maknode(IFSOCK | 0777, ndp);
d6213d15
BJ
349 if (ip == NULL) {
350 error = u.u_error; /* XXX */
351 u.u_error = 0; /* XXX */
352 return (error);
353 }
354 ip->i_socket = unp->unp_socket;
355 unp->unp_inode = ip;
6c0894dd 356 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
d6213d15
BJ
357 iunlock(ip); /* but keep reference */
358 return (0);
359}
360
4f083fd7 361unp_connect(so, nam)
d6213d15 362 struct socket *so;
4f083fd7 363 struct mbuf *nam;
d6213d15 364{
4f083fd7 365 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
4f083fd7 366 register struct inode *ip;
d6213d15 367 int error;
88a7a62a 368 register struct socket *so2;
715baff1 369 register struct nameidata *ndp = &u.u_nd;
d6213d15 370
715baff1 371 ndp->ni_dirp = soun->sun_path;
88a7a62a
SL
372 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
373 return (EMSGSIZE);
374 *(mtod(nam, caddr_t) + nam->m_len) = 0;
715baff1
KM
375 ndp->ni_nameiop = LOOKUP | FOLLOW;
376 ndp->ni_segflg = UIO_SYSSPACE;
377 ip = namei(ndp);
d6213d15
BJ
378 if (ip == 0) {
379 error = u.u_error;
380 u.u_error = 0;
5fe6f9d1 381 return (error); /* XXX */
d6213d15 382 }
9c40f33e
MK
383 if (access(ip, IWRITE)) {
384 error = u.u_error;
385 u.u_error = 0; /* XXX */
386 goto bad;
387 }
d6213d15
BJ
388 if ((ip->i_mode&IFMT) != IFSOCK) {
389 error = ENOTSOCK;
390 goto bad;
391 }
392 so2 = ip->i_socket;
393 if (so2 == 0) {
394 error = ECONNREFUSED;
395 goto bad;
396 }
5a48956d
SL
397 if (so->so_type != so2->so_type) {
398 error = EPROTOTYPE;
399 goto bad;
400 }
401 if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
402 ((so2->so_options&SO_ACCEPTCONN) == 0 ||
403 (so2 = sonewconn(so2)) == 0)) {
404 error = ECONNREFUSED;
405 goto bad;
406 }
d97afdcc 407 error = unp_connect2(so, so2);
88a7a62a
SL
408bad:
409 iput(ip);
410 return (error);
411}
412
d97afdcc 413unp_connect2(so, so2)
88a7a62a 414 register struct socket *so;
88a7a62a
SL
415 register struct socket *so2;
416{
417 register struct unpcb *unp = sotounpcb(so);
418 register struct unpcb *unp2;
419
420 if (so2->so_type != so->so_type)
421 return (EPROTOTYPE);
ccffacbd
SL
422 unp2 = sotounpcb(so2);
423 unp->unp_conn = unp2;
d6213d15
BJ
424 switch (so->so_type) {
425
426 case SOCK_DGRAM:
d6213d15
BJ
427 unp->unp_nextref = unp2->unp_refs;
428 unp2->unp_refs = unp;
9c40f33e 429 soisconnected(so);
d6213d15
BJ
430 break;
431
432 case SOCK_STREAM:
4f083fd7 433 unp2->unp_conn = unp;
ccffacbd
SL
434 soisconnected(so2);
435 soisconnected(so);
d6213d15
BJ
436 break;
437
438 default:
88a7a62a 439 panic("unp_connect2");
d6213d15 440 }
d6213d15 441 return (0);
d6213d15 442}
4f083fd7
SL
443
444unp_disconnect(unp)
445 struct unpcb *unp;
446{
447 register struct unpcb *unp2 = unp->unp_conn;
448
449 if (unp2 == 0)
450 return;
451 unp->unp_conn = 0;
4f083fd7
SL
452 switch (unp->unp_socket->so_type) {
453
454 case SOCK_DGRAM:
455 if (unp2->unp_refs == unp)
456 unp2->unp_refs = unp->unp_nextref;
457 else {
458 unp2 = unp2->unp_refs;
459 for (;;) {
460 if (unp2 == 0)
461 panic("unp_disconnect");
462 if (unp2->unp_nextref == unp)
463 break;
464 unp2 = unp2->unp_nextref;
465 }
466 unp2->unp_nextref = unp->unp_nextref;
467 }
468 unp->unp_nextref = 0;
c5935bca 469 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4f083fd7
SL
470 break;
471
472 case SOCK_STREAM:
ccffacbd 473 soisdisconnected(unp->unp_socket);
4f083fd7
SL
474 unp2->unp_conn = 0;
475 soisdisconnected(unp2->unp_socket);
4f083fd7
SL
476 break;
477 }
478}
479
88a7a62a 480#ifdef notdef
4f083fd7
SL
481unp_abort(unp)
482 struct unpcb *unp;
483{
484
485 unp_detach(unp);
486}
88a7a62a 487#endif
4f083fd7
SL
488
489/*ARGSUSED*/
490unp_usrclosed(unp)
491 struct unpcb *unp;
492{
493
494}
495
496unp_drop(unp, errno)
497 struct unpcb *unp;
498 int errno;
499{
d12671e0 500 struct socket *so = unp->unp_socket;
4f083fd7 501
d12671e0 502 so->so_error = errno;
4f083fd7 503 unp_disconnect(unp);
d12671e0
MK
504 if (so->so_head) {
505 so->so_pcb = (caddr_t) 0;
6c0894dd 506 m_freem(unp->unp_addr);
d12671e0
MK
507 (void) m_free(dtom(unp));
508 sofree(so);
509 }
4f083fd7
SL
510}
511
88a7a62a 512#ifdef notdef
4f083fd7
SL
513unp_drain()
514{
515
516}
88a7a62a
SL
517#endif
518
519unp_externalize(rights)
520 struct mbuf *rights;
521{
522 int newfds = rights->m_len / sizeof (int);
523 register int i;
524 register struct file **rp = mtod(rights, struct file **);
525 register struct file *fp;
526 int f;
527
528 if (newfds > ufavail()) {
529 for (i = 0; i < newfds; i++) {
530 fp = *rp;
531 unp_discard(fp);
532 *rp++ = 0;
533 }
534 return (EMSGSIZE);
535 }
536 for (i = 0; i < newfds; i++) {
537 f = ufalloc(0);
538 if (f < 0)
539 panic("unp_externalize");
540 fp = *rp;
541 u.u_ofile[f] = fp;
542 fp->f_msgcount--;
6c0894dd 543 unp_rights--;
bb3b4851 544 *(int *)rp++ = f;
88a7a62a
SL
545 }
546 return (0);
547}
548
549unp_internalize(rights)
550 struct mbuf *rights;
551{
552 register struct file **rp;
553 int oldfds = rights->m_len / sizeof (int);
554 register int i;
555 register struct file *fp;
556
557 rp = mtod(rights, struct file **);
44eb2da3 558 for (i = 0; i < oldfds; i++)
88a7a62a
SL
559 if (getf(*(int *)rp++) == 0)
560 return (EBADF);
561 rp = mtod(rights, struct file **);
44eb2da3 562 for (i = 0; i < oldfds; i++) {
88a7a62a
SL
563 fp = getf(*(int *)rp);
564 *rp++ = fp;
565 fp->f_count++;
566 fp->f_msgcount++;
6c0894dd 567 unp_rights++;
88a7a62a
SL
568 }
569 return (0);
570}
571
572int unp_defer, unp_gcing;
573int unp_mark();
261a8548 574extern struct domain unixdomain;
88a7a62a
SL
575
576unp_gc()
577{
578 register struct file *fp;
579 register struct socket *so;
580
581 if (unp_gcing)
582 return;
583 unp_gcing = 1;
584restart:
585 unp_defer = 0;
586 for (fp = file; fp < fileNFILE; fp++)
587 fp->f_flag &= ~(FMARK|FDEFER);
588 do {
589 for (fp = file; fp < fileNFILE; fp++) {
590 if (fp->f_count == 0)
591 continue;
592 if (fp->f_flag & FDEFER) {
593 fp->f_flag &= ~FDEFER;
594 unp_defer--;
595 } else {
596 if (fp->f_flag & FMARK)
597 continue;
598 if (fp->f_count == fp->f_msgcount)
599 continue;
600 fp->f_flag |= FMARK;
601 }
602 if (fp->f_type != DTYPE_SOCKET)
603 continue;
604 so = (struct socket *)fp->f_data;
261a8548 605 if (so->so_proto->pr_domain != &unixdomain ||
c5935bca 606 (so->so_proto->pr_flags&PR_RIGHTS) == 0)
88a7a62a
SL
607 continue;
608 if (so->so_rcv.sb_flags & SB_LOCK) {
609 sbwait(&so->so_rcv);
610 goto restart;
611 }
612 unp_scan(so->so_rcv.sb_mb, unp_mark);
613 }
614 } while (unp_defer);
615 for (fp = file; fp < fileNFILE; fp++) {
616 if (fp->f_count == 0)
617 continue;
6c0894dd
MK
618 if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
619 while (fp->f_msgcount)
620 unp_discard(fp);
88a7a62a
SL
621 }
622 unp_gcing = 0;
623}
624
261a8548
MK
625unp_dispose(m)
626 struct mbuf *m;
627{
628 int unp_discard();
629
148703ec
MK
630 if (m)
631 unp_scan(m, unp_discard);
261a8548
MK
632}
633
634unp_scan(m0, op)
635 register struct mbuf *m0;
88a7a62a
SL
636 int (*op)();
637{
261a8548 638 register struct mbuf *m;
88a7a62a
SL
639 register struct file **rp;
640 register int i;
148703ec 641 int qfds;
261a8548
MK
642
643 while (m0) {
644 for (m = m0; m; m = m->m_next)
645 if (m->m_type == MT_RIGHTS && m->m_len) {
646 qfds = m->m_len / sizeof (struct file *);
647 rp = mtod(m, struct file **);
648 for (i = 0; i < qfds; i++)
649 (*op)(*rp++);
650 break; /* XXX, but saves time */
651 }
148703ec 652 m0 = m0->m_act;
88a7a62a 653 }
88a7a62a
SL
654}
655
656unp_mark(fp)
657 struct file *fp;
658{
659
660 if (fp->f_flag & FMARK)
661 return;
662 unp_defer++;
663 fp->f_flag |= (FMARK|FDEFER);
664}
665
666unp_discard(fp)
667 struct file *fp;
668{
669
670 fp->f_msgcount--;
6c0894dd 671 unp_rights--;
44eb2da3 672 closef(fp);
88a7a62a 673}