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