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