xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 26365)
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.21 (Berkeley) 02/23/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 		break;
245 
246 	case PRU_SLOWTIMO:
247 		break;
248 
249 	default:
250 		panic("piusrreq");
251 	}
252 release:
253 	if (m)
254 		m_freem(m);
255 	return (error);
256 }
257 
258 /*
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.
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
267 int	unpst_sendspace = PIPSIZ;
268 int	unpst_recvspace = PIPSIZ;
269 int	unpdg_sendspace = 2*1024;	/* really max datagram size */
270 int	unpdg_recvspace = 4*1024;
271 
272 int	unp_rights;			/* file descriptors in flight */
273 
274 unp_attach(so)
275 	struct socket *so;
276 {
277 	register struct mbuf *m;
278 	register struct unpcb *unp;
279 	int error;
280 
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 	}
291 	if (error)
292 		return (error);
293 	m = m_getclr(M_DONTWAIT, MT_PCB);
294 	if (m == NULL)
295 		return (ENOBUFS);
296 	unp = mtod(m, struct unpcb *);
297 	so->so_pcb = (caddr_t)unp;
298 	unp->unp_socket = so;
299 	return (0);
300 }
301 
302 unp_detach(unp)
303 	register struct unpcb *unp;
304 {
305 
306 	if (unp->unp_inode) {
307 		unp->unp_inode->i_socket = 0;
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;
317 	m_freem(unp->unp_addr);
318 	(void) m_free(dtom(unp));
319 	if (unp_rights)
320 		unp_gc();
321 }
322 
323 unp_bind(unp, nam)
324 	struct unpcb *unp;
325 	struct mbuf *nam;
326 {
327 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
328 	register struct inode *ip;
329 	register struct nameidata *ndp = &u.u_nd;
330 	int error;
331 
332 	ndp->ni_dirp = soun->sun_path;
333 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
334 		return (EINVAL);
335 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
336 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
337 	ndp->ni_nameiop = CREATE | FOLLOW;
338 	ndp->ni_segflg = UIO_SYSSPACE;
339 	ip = namei(ndp);
340 	if (ip) {
341 		iput(ip);
342 		return (EADDRINUSE);
343 	}
344 	if (error = u.u_error) {
345 		u.u_error = 0;			/* XXX */
346 		return (error);
347 	}
348 	ip = maknode(IFSOCK | 0777, ndp);
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;
356 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
357 	iunlock(ip);			/* but keep reference */
358 	return (0);
359 }
360 
361 unp_connect(so, nam)
362 	struct socket *so;
363 	struct mbuf *nam;
364 {
365 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
366 	register struct inode *ip;
367 	int error;
368 	register struct socket *so2;
369 	register struct nameidata *ndp = &u.u_nd;
370 
371 	ndp->ni_dirp = soun->sun_path;
372 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
373 		return (EMSGSIZE);
374 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
375 	ndp->ni_nameiop = LOOKUP | FOLLOW;
376 	ndp->ni_segflg = UIO_SYSSPACE;
377 	ip = namei(ndp);
378 	if (ip == 0) {
379 		error = u.u_error;
380 		u.u_error = 0;
381 		return (error);		/* XXX */
382 	}
383 	if (access(ip, IWRITE)) {
384 		error = u.u_error;
385 		u.u_error = 0; 		/* XXX */
386 		goto bad;
387 	}
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 	}
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 	}
407 	error = unp_connect2(so, so2);
408 bad:
409 	iput(ip);
410 	return (error);
411 }
412 
413 unp_connect2(so, so2)
414 	register struct socket *so;
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);
422 	unp2 = sotounpcb(so2);
423 	unp->unp_conn = unp2;
424 	switch (so->so_type) {
425 
426 	case SOCK_DGRAM:
427 		unp->unp_nextref = unp2->unp_refs;
428 		unp2->unp_refs = unp;
429 		soisconnected(so);
430 		break;
431 
432 	case SOCK_STREAM:
433 		unp2->unp_conn = unp;
434 		soisconnected(so2);
435 		soisconnected(so);
436 		break;
437 
438 	default:
439 		panic("unp_connect2");
440 	}
441 	return (0);
442 }
443 
444 unp_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;
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;
469 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
470 		break;
471 
472 	case SOCK_STREAM:
473 		soisdisconnected(unp->unp_socket);
474 		unp2->unp_conn = 0;
475 		soisdisconnected(unp2->unp_socket);
476 		break;
477 	}
478 }
479 
480 #ifdef notdef
481 unp_abort(unp)
482 	struct unpcb *unp;
483 {
484 
485 	unp_detach(unp);
486 }
487 #endif
488 
489 /*ARGSUSED*/
490 unp_usrclosed(unp)
491 	struct unpcb *unp;
492 {
493 
494 }
495 
496 unp_drop(unp, errno)
497 	struct unpcb *unp;
498 	int errno;
499 {
500 	struct socket *so = unp->unp_socket;
501 
502 	so->so_error = errno;
503 	unp_disconnect(unp);
504 	if (so->so_head) {
505 		so->so_pcb = (caddr_t) 0;
506 		m_freem(unp->unp_addr);
507 		(void) m_free(dtom(unp));
508 		sofree(so);
509 	}
510 }
511 
512 #ifdef notdef
513 unp_drain()
514 {
515 
516 }
517 #endif
518 
519 unp_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--;
543 		unp_rights--;
544 		*(int *)rp++ = f;
545 	}
546 	return (0);
547 }
548 
549 unp_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 **);
558 	for (i = 0; i < oldfds; i++)
559 		if (getf(*(int *)rp++) == 0)
560 			return (EBADF);
561 	rp = mtod(rights, struct file **);
562 	for (i = 0; i < oldfds; i++) {
563 		fp = getf(*(int *)rp);
564 		*rp++ = fp;
565 		fp->f_count++;
566 		fp->f_msgcount++;
567 		unp_rights++;
568 	}
569 	return (0);
570 }
571 
572 int	unp_defer, unp_gcing;
573 int	unp_mark();
574 extern	struct domain unixdomain;
575 
576 unp_gc()
577 {
578 	register struct file *fp;
579 	register struct socket *so;
580 
581 	if (unp_gcing)
582 		return;
583 	unp_gcing = 1;
584 restart:
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;
605 			if (so->so_proto->pr_domain != &unixdomain ||
606 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
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;
618 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
619 			while (fp->f_msgcount)
620 				unp_discard(fp);
621 	}
622 	unp_gcing = 0;
623 }
624 
625 unp_dispose(m)
626 	struct mbuf *m;
627 {
628 	int unp_discard();
629 
630 	if (m)
631 		unp_scan(m, unp_discard);
632 }
633 
634 unp_scan(m0, op)
635 	register struct mbuf *m0;
636 	int (*op)();
637 {
638 	register struct mbuf *m;
639 	register struct file **rp;
640 	register int i;
641 	int qfds;
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 			}
652 		m0 = m0->m_act;
653 	}
654 }
655 
656 unp_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 
666 unp_discard(fp)
667 	struct file *fp;
668 {
669 
670 	fp->f_msgcount--;
671 	unp_rights--;
672 	closef(fp);
673 }
674