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