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