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