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