xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 14049)
1 /*	uipc_usrreq.c	1.15	83/07/21	*/
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/nami.h"
14 #include "../h/file.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 	case PRU_SENSE:
202 		error = EOPNOTSUPP;
203 		break;
204 /* END UNIMPLEMENTED HOOKS */
205 
206 	case PRU_RCVOOB:
207 		break;
208 
209 	case PRU_SENDOOB:
210 		break;
211 
212 	case PRU_SOCKADDR:
213 		break;
214 
215 	case PRU_SLOWTIMO:
216 		break;
217 
218 	default:
219 		panic("piusrreq");
220 	}
221 release:
222 	if (m)
223 		m_freem(m);
224 	return (error);
225 }
226 
227 /* SHOULD BE PIPSIZ and 0 */
228 int	unp_sendspace = 1024*2;
229 int	unp_recvspace = 1024*2;
230 
231 unp_attach(so)
232 	struct socket *so;
233 {
234 	register struct mbuf *m;
235 	register struct unpcb *unp;
236 	int error;
237 
238 	error = soreserve(so, unp_sendspace, unp_recvspace);
239 	if (error)
240 		return (error);
241 	m = m_getclr(M_DONTWAIT, MT_PCB);
242 	if (m == NULL)
243 		return (ENOBUFS);
244 	unp = mtod(m, struct unpcb *);
245 	so->so_pcb = (caddr_t)unp;
246 	unp->unp_socket = so;
247 	return (0);
248 }
249 
250 unp_detach(unp)
251 	register struct unpcb *unp;
252 {
253 
254 	if (unp->unp_inode) {
255 		irele(unp->unp_inode);
256 		unp->unp_inode = 0;
257 	}
258 	if (unp->unp_conn)
259 		unp_disconnect(unp);
260 	while (unp->unp_refs)
261 		unp_drop(unp->unp_refs, ECONNRESET);
262 	soisdisconnected(unp->unp_socket);
263 	unp->unp_socket->so_pcb = 0;
264 	m_freem(unp->unp_remaddr);
265 	(void) m_free(dtom(unp));
266 }
267 
268 unp_bind(unp, nam)
269 	struct unpcb *unp;
270 	struct mbuf *nam;
271 {
272 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
273 	register struct inode *ip;
274 	extern schar();
275 	int error;
276 
277 	u.u_dirp = soun->sun_path;
278 	if (nam->m_len == MLEN)
279 		return (EINVAL);
280 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
281 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
282 	ip = namei(schar, CREATE, 1);
283 	if (ip) {
284 		iput(ip);
285 		return (EADDRINUSE);
286 	}
287 	if (error = u.u_error) {
288 		u.u_error = 0;			/* XXX */
289 		return (error);
290 	}
291 	ip = maknode(IFSOCK | 0777);
292 	if (ip == NULL) {
293 		error = u.u_error;		/* XXX */
294 		u.u_error = 0;			/* XXX */
295 		return (error);
296 	}
297 	ip->i_socket = unp->unp_socket;
298 	unp->unp_inode = ip;
299 	iunlock(ip);			/* but keep reference */
300 	return (0);
301 }
302 
303 unp_connect(so, nam)
304 	struct socket *so;
305 	struct mbuf *nam;
306 {
307 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
308 	register struct inode *ip;
309 	int error;
310 	register struct socket *so2;
311 
312 	u.u_dirp = soun->sun_path;
313 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
314 		return (EMSGSIZE);
315 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
316 	ip = namei(schar, LOOKUP, 1);
317 	if (ip == 0) {
318 		error = u.u_error;
319 		u.u_error = 0;
320 		return (error);		/* XXX */
321 	}
322 	if ((ip->i_mode&IFMT) != IFSOCK) {
323 		error = ENOTSOCK;
324 		goto bad;
325 	}
326 	so2 = ip->i_socket;
327 	if (so2 == 0) {
328 		error = ECONNREFUSED;
329 		goto bad;
330 	}
331 	if (so->so_type != so2->so_type) {
332 		error = EPROTOTYPE;
333 		goto bad;
334 	}
335 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
336 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
337 	     (so2 = sonewconn(so2)) == 0)) {
338 		error = ECONNREFUSED;
339 		goto bad;
340 	}
341 	error = unp_connect2(so, nam, so2);
342 bad:
343 	iput(ip);
344 	return (error);
345 }
346 
347 unp_connect2(so, sonam, so2)
348 	register struct socket *so;
349 	struct mbuf *sonam;
350 	register struct socket *so2;
351 {
352 	register struct unpcb *unp = sotounpcb(so);
353 	register struct unpcb *unp2;
354 
355 	if (so2->so_type != so->so_type)
356 		return (EPROTOTYPE);
357 	unp2 = sotounpcb(so2);
358 	unp->unp_conn = unp2;
359 	switch (so->so_type) {
360 
361 	case SOCK_DGRAM:
362 		unp->unp_nextref = unp2->unp_refs;
363 		unp2->unp_refs = unp;
364 		break;
365 
366 	case SOCK_STREAM:
367 		unp2->unp_conn = unp;
368 		if (sonam)
369 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
370 		soisconnected(so2);
371 		soisconnected(so);
372 		break;
373 
374 	default:
375 		panic("unp_connect2");
376 	}
377 	return (0);
378 }
379 
380 unp_disconnect(unp)
381 	struct unpcb *unp;
382 {
383 	register struct unpcb *unp2 = unp->unp_conn;
384 
385 	if (unp2 == 0)
386 		return;
387 	unp->unp_conn = 0;
388 	switch (unp->unp_socket->so_type) {
389 
390 	case SOCK_DGRAM:
391 		if (unp2->unp_refs == unp)
392 			unp2->unp_refs = unp->unp_nextref;
393 		else {
394 			unp2 = unp2->unp_refs;
395 			for (;;) {
396 				if (unp2 == 0)
397 					panic("unp_disconnect");
398 				if (unp2->unp_nextref == unp)
399 					break;
400 				unp2 = unp2->unp_nextref;
401 			}
402 			unp2->unp_nextref = unp->unp_nextref;
403 		}
404 		unp->unp_nextref = 0;
405 		break;
406 
407 	case SOCK_STREAM:
408 		soisdisconnected(unp->unp_socket);
409 		unp2->unp_conn = 0;
410 		soisdisconnected(unp2->unp_socket);
411 		break;
412 	}
413 }
414 
415 #ifdef notdef
416 unp_abort(unp)
417 	struct unpcb *unp;
418 {
419 
420 	unp_detach(unp);
421 }
422 #endif
423 
424 /*ARGSUSED*/
425 unp_usrclosed(unp)
426 	struct unpcb *unp;
427 {
428 
429 }
430 
431 unp_drop(unp, errno)
432 	struct unpcb *unp;
433 	int errno;
434 {
435 
436 	unp->unp_socket->so_error = errno;
437 	unp_disconnect(unp);
438 }
439 
440 #ifdef notdef
441 unp_drain()
442 {
443 
444 }
445 #endif
446 
447 unp_externalize(rights)
448 	struct mbuf *rights;
449 {
450 	int newfds = rights->m_len / sizeof (int);
451 	register int i;
452 	register struct file **rp = mtod(rights, struct file **);
453 	register struct file *fp;
454 	int f;
455 
456 	if (newfds > ufavail()) {
457 		for (i = 0; i < newfds; i++) {
458 			fp = *rp;
459 			unp_discard(fp);
460 			*rp++ = 0;
461 		}
462 		return (EMSGSIZE);
463 	}
464 	for (i = 0; i < newfds; i++) {
465 		f = ufalloc(0);
466 		if (f < 0)
467 			panic("unp_externalize");
468 		fp = *rp;
469 		u.u_ofile[f] = fp;
470 		fp->f_msgcount--;
471 		*(int *)rp = f;
472 	}
473 	return (0);
474 }
475 
476 unp_internalize(rights)
477 	struct mbuf *rights;
478 {
479 	register struct file **rp;
480 	int oldfds = rights->m_len / sizeof (int);
481 	register int i;
482 	register struct file *fp;
483 
484 	rp = mtod(rights, struct file **);
485 	for (i = 0; i < oldfds; i++)
486 		if (getf(*(int *)rp++) == 0)
487 			return (EBADF);
488 	rp = mtod(rights, struct file **);
489 	for (i = 0; i < oldfds; i++) {
490 		fp = getf(*(int *)rp);
491 		*rp++ = fp;
492 		fp->f_count++;
493 		fp->f_msgcount++;
494 	}
495 	return (0);
496 }
497 
498 int	unp_defer, unp_gcing;
499 int	unp_mark();
500 
501 unp_gc()
502 {
503 	register struct file *fp;
504 	register struct socket *so;
505 
506 	if (unp_gcing)
507 		return;
508 	unp_gcing = 1;
509 restart:
510 	unp_defer = 0;
511 	for (fp = file; fp < fileNFILE; fp++)
512 		fp->f_flag &= ~(FMARK|FDEFER);
513 	do {
514 		for (fp = file; fp < fileNFILE; fp++) {
515 			if (fp->f_count == 0)
516 				continue;
517 			if (fp->f_flag & FDEFER) {
518 				fp->f_flag &= ~FDEFER;
519 				unp_defer--;
520 			} else {
521 				if (fp->f_flag & FMARK)
522 					continue;
523 				if (fp->f_count == fp->f_msgcount)
524 					continue;
525 				fp->f_flag |= FMARK;
526 			}
527 			if (fp->f_type != DTYPE_SOCKET)
528 				continue;
529 			so = (struct socket *)fp->f_data;
530 			if (so->so_proto->pr_family != AF_UNIX ||
531 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
532 				continue;
533 			if (so->so_rcv.sb_flags & SB_LOCK) {
534 				sbwait(&so->so_rcv);
535 				goto restart;
536 			}
537 			unp_scan(so->so_rcv.sb_mb, unp_mark);
538 		}
539 	} while (unp_defer);
540 	for (fp = file; fp < fileNFILE; fp++) {
541 		if (fp->f_count == 0)
542 			continue;
543 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
544 			if (fp->f_type != DTYPE_SOCKET)
545 				panic("unp_gc");
546 			(void) soshutdown((struct socket *)fp->f_data, 0);
547 		}
548 	}
549 	unp_gcing = 0;
550 }
551 
552 unp_scan(m, op)
553 	register struct mbuf *m;
554 	int (*op)();
555 {
556 	register struct file **rp;
557 	register int i;
558 	int qfds;
559 
560 	while (m) {
561 		m = m->m_next;
562 		if (m == 0)
563 			goto bad;
564 		if (m->m_len) {
565 			qfds = m->m_len / sizeof (struct file *);
566 			rp = mtod(m, struct file **);
567 			for (i = 0; i < qfds; i++)
568 				(*op)(*rp++);
569 		}
570 		do {
571 			m = m->m_next;
572 			if (m == 0)
573 				goto bad;
574 		} while (m->m_act == 0);
575 		m = m->m_next;
576 	}
577 	return;
578 bad:
579 	panic("unp_gcscan");
580 }
581 
582 unp_mark(fp)
583 	struct file *fp;
584 {
585 
586 	if (fp->f_flag & FMARK)
587 		return;
588 	unp_defer++;
589 	fp->f_flag |= (FMARK|FDEFER);
590 }
591 
592 unp_discard(fp)
593 	struct file *fp;
594 {
595 
596 	fp->f_msgcount--;
597 	closef(fp);
598 }
599