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