xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 34447)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  *
12  *	@(#)uipc_usrreq.c	7.5 (Berkeley) 05/24/88
13  */
14 
15 #include "param.h"
16 #include "dir.h"
17 #include "user.h"
18 #include "mbuf.h"
19 #include "domain.h"
20 #include "protosw.h"
21 #include "socket.h"
22 #include "socketvar.h"
23 #include "unpcb.h"
24 #include "un.h"
25 #include "inode.h"
26 #include "file.h"
27 #include "stat.h"
28 
29 /*
30  * Unix communications domain.
31  *
32  * TODO:
33  *	SEQPACKET, RDM
34  *	rethink name space problems
35  *	need a proper out-of-band
36  */
37 struct	sockaddr sun_noname = { AF_UNIX };
38 ino_t	unp_ino;			/* prototype for fake inode numbers */
39 
40 /*ARGSUSED*/
41 uipc_usrreq(so, req, m, nam, rights)
42 	struct socket *so;
43 	int req;
44 	struct mbuf *m, *nam, *rights;
45 {
46 	struct unpcb *unp = sotounpcb(so);
47 	register struct socket *so2;
48 	int error = 0;
49 
50 	if (req == PRU_CONTROL)
51 		return (EOPNOTSUPP);
52 	if (req != PRU_SEND && rights && rights->m_len) {
53 		error = EOPNOTSUPP;
54 		goto release;
55 	}
56 	if (unp == 0 && req != PRU_ATTACH) {
57 		error = EINVAL;
58 		goto release;
59 	}
60 	switch (req) {
61 
62 	case PRU_ATTACH:
63 		if (unp) {
64 			error = EISCONN;
65 			break;
66 		}
67 		error = unp_attach(so);
68 		break;
69 
70 	case PRU_DETACH:
71 		unp_detach(unp);
72 		break;
73 
74 	case PRU_BIND:
75 		error = unp_bind(unp, nam);
76 		break;
77 
78 	case PRU_LISTEN:
79 		if (unp->unp_inode == 0)
80 			error = EINVAL;
81 		break;
82 
83 	case PRU_CONNECT:
84 		error = unp_connect(so, nam);
85 		break;
86 
87 	case PRU_CONNECT2:
88 		error = unp_connect2(so, (struct socket *)nam);
89 		break;
90 
91 	case PRU_DISCONNECT:
92 		unp_disconnect(unp);
93 		break;
94 
95 	case PRU_ACCEPT:
96 		/*
97 		 * Pass back name of connected socket,
98 		 * if it was bound and we are still connected
99 		 * (our peer may have closed already!).
100 		 */
101 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
102 			nam->m_len = unp->unp_conn->unp_addr->m_len;
103 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
104 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
105 		} else {
106 			nam->m_len = sizeof(sun_noname);
107 			*(mtod(nam, struct sockaddr *)) = sun_noname;
108 		}
109 		break;
110 
111 	case PRU_SHUTDOWN:
112 		socantsendmore(so);
113 		unp_usrclosed(unp);
114 		break;
115 
116 	case PRU_RCVD:
117 		switch (so->so_type) {
118 
119 		case SOCK_DGRAM:
120 			panic("uipc 1");
121 			/*NOTREACHED*/
122 
123 		case SOCK_STREAM:
124 #define	rcv (&so->so_rcv)
125 #define snd (&so2->so_snd)
126 			if (unp->unp_conn == 0)
127 				break;
128 			so2 = unp->unp_conn->unp_socket;
129 			/*
130 			 * Adjust backpressure on sender
131 			 * and wakeup any waiting to write.
132 			 */
133 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
134 			unp->unp_mbcnt = rcv->sb_mbcnt;
135 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
136 			unp->unp_cc = rcv->sb_cc;
137 			sowwakeup(so2);
138 #undef snd
139 #undef rcv
140 			break;
141 
142 		default:
143 			panic("uipc 2");
144 		}
145 		break;
146 
147 	case PRU_SEND:
148 		if (rights) {
149 			error = unp_internalize(rights);
150 			if (error)
151 				break;
152 		}
153 		switch (so->so_type) {
154 
155 		case SOCK_DGRAM: {
156 			struct sockaddr *from;
157 
158 			if (nam) {
159 				if (unp->unp_conn) {
160 					error = EISCONN;
161 					break;
162 				}
163 				error = unp_connect(so, nam);
164 				if (error)
165 					break;
166 			} else {
167 				if (unp->unp_conn == 0) {
168 					error = ENOTCONN;
169 					break;
170 				}
171 			}
172 			so2 = unp->unp_conn->unp_socket;
173 			if (unp->unp_addr)
174 				from = mtod(unp->unp_addr, struct sockaddr *);
175 			else
176 				from = &sun_noname;
177 			if (sbspace(&so2->so_rcv) > 0 &&
178 			    sbappendaddr(&so2->so_rcv, from, m, rights)) {
179 				sorwakeup(so2);
180 				m = 0;
181 			} else
182 				error = ENOBUFS;
183 			if (nam)
184 				unp_disconnect(unp);
185 			break;
186 		}
187 
188 		case SOCK_STREAM:
189 #define	rcv (&so2->so_rcv)
190 #define	snd (&so->so_snd)
191 			if (so->so_state & SS_CANTSENDMORE) {
192 				error = EPIPE;
193 				break;
194 			}
195 			if (unp->unp_conn == 0)
196 				panic("uipc 3");
197 			so2 = unp->unp_conn->unp_socket;
198 			/*
199 			 * Send to paired receive port, and then reduce
200 			 * send buffer hiwater marks to maintain backpressure.
201 			 * Wake up readers.
202 			 */
203 			if (rights)
204 				(void)sbappendrights(rcv, m, rights);
205 			else
206 				sbappend(rcv, m);
207 			snd->sb_mbmax -=
208 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
209 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
210 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
211 			unp->unp_conn->unp_cc = rcv->sb_cc;
212 			sorwakeup(so2);
213 			m = 0;
214 #undef snd
215 #undef rcv
216 			break;
217 
218 		default:
219 			panic("uipc 4");
220 		}
221 		break;
222 
223 	case PRU_ABORT:
224 		unp_drop(unp, ECONNABORTED);
225 		break;
226 
227 	case PRU_SENSE:
228 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
229 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
230 			so2 = unp->unp_conn->unp_socket;
231 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
232 		}
233 		((struct stat *) m)->st_dev = NODEV;
234 		if (unp->unp_ino == 0)
235 			unp->unp_ino = unp_ino++;
236 		((struct stat *) m)->st_ino = unp->unp_ino;
237 		return (0);
238 
239 	case PRU_RCVOOB:
240 		return (EOPNOTSUPP);
241 
242 	case PRU_SENDOOB:
243 		error = EOPNOTSUPP;
244 		break;
245 
246 	case PRU_SOCKADDR:
247 		if (unp->unp_addr) {
248 			nam->m_len = unp->unp_addr->m_len;
249 			bcopy(mtod(unp->unp_addr, caddr_t),
250 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
251 		} else
252 			nam->m_len = 0;
253 		break;
254 
255 	case PRU_PEERADDR:
256 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
257 			nam->m_len = unp->unp_conn->unp_addr->m_len;
258 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
259 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
260 		} else
261 			nam->m_len = 0;
262 		break;
263 
264 	case PRU_SLOWTIMO:
265 		break;
266 
267 	default:
268 		panic("piusrreq");
269 	}
270 release:
271 	if (m)
272 		m_freem(m);
273 	return (error);
274 }
275 
276 /*
277  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
278  * for stream sockets, although the total for sender and receiver is
279  * actually only PIPSIZ.
280  * Datagram sockets really use the sendspace as the maximum datagram size,
281  * and don't really want to reserve the sendspace.  Their recvspace should
282  * be large enough for at least one max-size datagram plus address.
283  */
284 #define	PIPSIZ	4096
285 int	unpst_sendspace = PIPSIZ;
286 int	unpst_recvspace = PIPSIZ;
287 int	unpdg_sendspace = 2*1024;	/* really max datagram size */
288 int	unpdg_recvspace = 4*1024;
289 
290 int	unp_rights;			/* file descriptors in flight */
291 
292 unp_attach(so)
293 	struct socket *so;
294 {
295 	register struct mbuf *m;
296 	register struct unpcb *unp;
297 	int error;
298 
299 	switch (so->so_type) {
300 
301 	case SOCK_STREAM:
302 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
303 		break;
304 
305 	case SOCK_DGRAM:
306 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
307 		break;
308 	}
309 	if (error)
310 		return (error);
311 	m = m_getclr(M_DONTWAIT, MT_PCB);
312 	if (m == NULL)
313 		return (ENOBUFS);
314 	unp = mtod(m, struct unpcb *);
315 	so->so_pcb = (caddr_t)unp;
316 	unp->unp_socket = so;
317 	return (0);
318 }
319 
320 unp_detach(unp)
321 	register struct unpcb *unp;
322 {
323 
324 	if (unp->unp_inode) {
325 		unp->unp_inode->i_socket = 0;
326 		irele(unp->unp_inode);
327 		unp->unp_inode = 0;
328 	}
329 	if (unp->unp_conn)
330 		unp_disconnect(unp);
331 	while (unp->unp_refs)
332 		unp_drop(unp->unp_refs, ECONNRESET);
333 	soisdisconnected(unp->unp_socket);
334 	unp->unp_socket->so_pcb = 0;
335 	m_freem(unp->unp_addr);
336 	(void) m_free(dtom(unp));
337 	if (unp_rights)
338 		unp_gc();
339 }
340 
341 unp_bind(unp, nam)
342 	struct unpcb *unp;
343 	struct mbuf *nam;
344 {
345 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
346 	register struct inode *ip;
347 	register struct nameidata *ndp = &u.u_nd;
348 	int error;
349 
350 	ndp->ni_dirp = soun->sun_path;
351 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
352 		return (EINVAL);
353 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
354 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
355 	ndp->ni_nameiop = CREATE | FOLLOW;
356 	ndp->ni_segflg = UIO_SYSSPACE;
357 	ip = namei(ndp);
358 	if (ip) {
359 		iput(ip);
360 		return (EADDRINUSE);
361 	}
362 	if (error = u.u_error) {
363 		u.u_error = 0;			/* XXX */
364 		return (error);
365 	}
366 	ip = maknode(IFSOCK | 0777, ndp);
367 	if (ip == NULL) {
368 		error = u.u_error;		/* XXX */
369 		u.u_error = 0;			/* XXX */
370 		return (error);
371 	}
372 	ip->i_socket = unp->unp_socket;
373 	unp->unp_inode = ip;
374 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
375 	iunlock(ip);			/* but keep reference */
376 	return (0);
377 }
378 
379 unp_connect(so, nam)
380 	struct socket *so;
381 	struct mbuf *nam;
382 {
383 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
384 	register struct inode *ip;
385 	register struct socket *so2, *so3;
386 	register struct nameidata *ndp = &u.u_nd;
387 	struct unpcb *unp2, *unp3;
388 	int error;
389 
390 	ndp->ni_dirp = soun->sun_path;
391 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
392 		return (EMSGSIZE);
393 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
394 	ndp->ni_nameiop = LOOKUP | FOLLOW;
395 	ndp->ni_segflg = UIO_SYSSPACE;
396 	ip = namei(ndp);
397 	if (ip == 0) {
398 		error = u.u_error;
399 		u.u_error = 0;
400 		return (error);		/* XXX */
401 	}
402 	if (access(ip, IWRITE)) {
403 		error = u.u_error;
404 		u.u_error = 0; 		/* XXX */
405 		goto bad;
406 	}
407 	if ((ip->i_mode&IFMT) != IFSOCK) {
408 		error = ENOTSOCK;
409 		goto bad;
410 	}
411 	so2 = ip->i_socket;
412 	if (so2 == 0) {
413 		error = ECONNREFUSED;
414 		goto bad;
415 	}
416 	if (so->so_type != so2->so_type) {
417 		error = EPROTOTYPE;
418 		goto bad;
419 	}
420 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
421 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
422 		    (so3 = sonewconn(so2)) == 0) {
423 			error = ECONNREFUSED;
424 			goto bad;
425 		}
426 		unp2 = sotounpcb(so2);
427 		unp3 = sotounpcb(so3);
428 		if (unp2->unp_addr)
429 			unp3->unp_addr = m_copy(unp2->unp_addr, 0, M_COPYALL);
430 		so2 = so3;
431 	}
432 	error = unp_connect2(so, so2);
433 bad:
434 	iput(ip);
435 	return (error);
436 }
437 
438 unp_connect2(so, so2)
439 	register struct socket *so;
440 	register struct socket *so2;
441 {
442 	register struct unpcb *unp = sotounpcb(so);
443 	register struct unpcb *unp2;
444 
445 	if (so2->so_type != so->so_type)
446 		return (EPROTOTYPE);
447 	unp2 = sotounpcb(so2);
448 	unp->unp_conn = unp2;
449 	switch (so->so_type) {
450 
451 	case SOCK_DGRAM:
452 		unp->unp_nextref = unp2->unp_refs;
453 		unp2->unp_refs = unp;
454 		soisconnected(so);
455 		break;
456 
457 	case SOCK_STREAM:
458 		unp2->unp_conn = unp;
459 		soisconnected(so2);
460 		soisconnected(so);
461 		break;
462 
463 	default:
464 		panic("unp_connect2");
465 	}
466 	return (0);
467 }
468 
469 unp_disconnect(unp)
470 	struct unpcb *unp;
471 {
472 	register struct unpcb *unp2 = unp->unp_conn;
473 
474 	if (unp2 == 0)
475 		return;
476 	unp->unp_conn = 0;
477 	switch (unp->unp_socket->so_type) {
478 
479 	case SOCK_DGRAM:
480 		if (unp2->unp_refs == unp)
481 			unp2->unp_refs = unp->unp_nextref;
482 		else {
483 			unp2 = unp2->unp_refs;
484 			for (;;) {
485 				if (unp2 == 0)
486 					panic("unp_disconnect");
487 				if (unp2->unp_nextref == unp)
488 					break;
489 				unp2 = unp2->unp_nextref;
490 			}
491 			unp2->unp_nextref = unp->unp_nextref;
492 		}
493 		unp->unp_nextref = 0;
494 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
495 		break;
496 
497 	case SOCK_STREAM:
498 		soisdisconnected(unp->unp_socket);
499 		unp2->unp_conn = 0;
500 		soisdisconnected(unp2->unp_socket);
501 		break;
502 	}
503 }
504 
505 #ifdef notdef
506 unp_abort(unp)
507 	struct unpcb *unp;
508 {
509 
510 	unp_detach(unp);
511 }
512 #endif
513 
514 /*ARGSUSED*/
515 unp_usrclosed(unp)
516 	struct unpcb *unp;
517 {
518 
519 }
520 
521 unp_drop(unp, errno)
522 	struct unpcb *unp;
523 	int errno;
524 {
525 	struct socket *so = unp->unp_socket;
526 
527 	so->so_error = errno;
528 	unp_disconnect(unp);
529 	if (so->so_head) {
530 		so->so_pcb = (caddr_t) 0;
531 		m_freem(unp->unp_addr);
532 		(void) m_free(dtom(unp));
533 		sofree(so);
534 	}
535 }
536 
537 #ifdef notdef
538 unp_drain()
539 {
540 
541 }
542 #endif
543 
544 unp_externalize(rights)
545 	struct mbuf *rights;
546 {
547 	int newfds = rights->m_len / sizeof (int);
548 	register int i;
549 	register struct file **rp = mtod(rights, struct file **);
550 	register struct file *fp;
551 	int f;
552 
553 	if (newfds > ufavail()) {
554 		for (i = 0; i < newfds; i++) {
555 			fp = *rp;
556 			unp_discard(fp);
557 			*rp++ = 0;
558 		}
559 		return (EMSGSIZE);
560 	}
561 	for (i = 0; i < newfds; i++) {
562 		f = ufalloc(0);
563 		if (f < 0)
564 			panic("unp_externalize");
565 		fp = *rp;
566 		u.u_ofile[f] = fp;
567 		fp->f_msgcount--;
568 		unp_rights--;
569 		*(int *)rp++ = f;
570 	}
571 	return (0);
572 }
573 
574 unp_internalize(rights)
575 	struct mbuf *rights;
576 {
577 	register struct file **rp;
578 	int oldfds = rights->m_len / sizeof (int);
579 	register int i;
580 	register struct file *fp;
581 
582 	rp = mtod(rights, struct file **);
583 	for (i = 0; i < oldfds; i++)
584 		if (getf(*(int *)rp++) == 0)
585 			return (EBADF);
586 	rp = mtod(rights, struct file **);
587 	for (i = 0; i < oldfds; i++) {
588 		fp = getf(*(int *)rp);
589 		*rp++ = fp;
590 		fp->f_count++;
591 		fp->f_msgcount++;
592 		unp_rights++;
593 	}
594 	return (0);
595 }
596 
597 int	unp_defer, unp_gcing;
598 int	unp_mark();
599 extern	struct domain unixdomain;
600 
601 unp_gc()
602 {
603 	register struct file *fp;
604 	register struct socket *so;
605 
606 	if (unp_gcing)
607 		return;
608 	unp_gcing = 1;
609 restart:
610 	unp_defer = 0;
611 	for (fp = file; fp < fileNFILE; fp++)
612 		fp->f_flag &= ~(FMARK|FDEFER);
613 	do {
614 		for (fp = file; fp < fileNFILE; fp++) {
615 			if (fp->f_count == 0)
616 				continue;
617 			if (fp->f_flag & FDEFER) {
618 				fp->f_flag &= ~FDEFER;
619 				unp_defer--;
620 			} else {
621 				if (fp->f_flag & FMARK)
622 					continue;
623 				if (fp->f_count == fp->f_msgcount)
624 					continue;
625 				fp->f_flag |= FMARK;
626 			}
627 			if (fp->f_type != DTYPE_SOCKET ||
628 			    (so = (struct socket *)fp->f_data) == 0)
629 				continue;
630 			if (so->so_proto->pr_domain != &unixdomain ||
631 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
632 				continue;
633 			if (so->so_rcv.sb_flags & SB_LOCK) {
634 				sbwait(&so->so_rcv);
635 				goto restart;
636 			}
637 			unp_scan(so->so_rcv.sb_mb, unp_mark);
638 		}
639 	} while (unp_defer);
640 	for (fp = file; fp < fileNFILE; fp++) {
641 		if (fp->f_count == 0)
642 			continue;
643 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
644 			while (fp->f_msgcount)
645 				unp_discard(fp);
646 	}
647 	unp_gcing = 0;
648 }
649 
650 unp_dispose(m)
651 	struct mbuf *m;
652 {
653 	int unp_discard();
654 
655 	if (m)
656 		unp_scan(m, unp_discard);
657 }
658 
659 unp_scan(m0, op)
660 	register struct mbuf *m0;
661 	int (*op)();
662 {
663 	register struct mbuf *m;
664 	register struct file **rp;
665 	register int i;
666 	int qfds;
667 
668 	while (m0) {
669 		for (m = m0; m; m = m->m_next)
670 			if (m->m_type == MT_RIGHTS && m->m_len) {
671 				qfds = m->m_len / sizeof (struct file *);
672 				rp = mtod(m, struct file **);
673 				for (i = 0; i < qfds; i++)
674 					(*op)(*rp++);
675 				break;		/* XXX, but saves time */
676 			}
677 		m0 = m0->m_act;
678 	}
679 }
680 
681 unp_mark(fp)
682 	struct file *fp;
683 {
684 
685 	if (fp->f_flag & FMARK)
686 		return;
687 	unp_defer++;
688 	fp->f_flag |= (FMARK|FDEFER);
689 }
690 
691 unp_discard(fp)
692 	struct file *fp;
693 {
694 
695 	fp->f_msgcount--;
696 	unp_rights--;
697 	closef(fp);
698 }
699