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