xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 13119)
1 /*	uipc_usrreq.c	1.14	83/06/14	*/
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 	switch (so->so_type) {
358 
359 	case SOCK_DGRAM:
360 		unp2 = sotounpcb(so2);
361 		unp->unp_conn = unp2;
362 		unp->unp_nextref = unp2->unp_refs;
363 		unp2->unp_refs = unp;
364 		break;
365 
366 	case SOCK_STREAM:
367 		unp2 = sotounpcb(so2);
368 		unp->unp_conn = unp2;
369 		unp2->unp_conn = unp;
370 		if (sonam)
371 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
372 		break;
373 
374 	default:
375 		panic("unp_connect2");
376 	}
377 	soisconnected(so2);
378 	soisconnected(so);
379 	return (0);
380 }
381 
382 unp_disconnect(unp)
383 	struct unpcb *unp;
384 {
385 	register struct unpcb *unp2 = unp->unp_conn;
386 
387 	if (unp2 == 0)
388 		return;
389 	unp->unp_conn = 0;
390 	soisdisconnected(unp->unp_socket);
391 	switch (unp->unp_socket->so_type) {
392 
393 	case SOCK_DGRAM:
394 		if (unp2->unp_refs == unp)
395 			unp2->unp_refs = unp->unp_nextref;
396 		else {
397 			unp2 = unp2->unp_refs;
398 			for (;;) {
399 				if (unp2 == 0)
400 					panic("unp_disconnect");
401 				if (unp2->unp_nextref == unp)
402 					break;
403 				unp2 = unp2->unp_nextref;
404 			}
405 			unp2->unp_nextref = unp->unp_nextref;
406 		}
407 		unp->unp_nextref = 0;
408 		break;
409 
410 	case SOCK_STREAM:
411 		unp2->unp_conn = 0;
412 		soisdisconnected(unp2->unp_socket);
413 		break;
414 	}
415 }
416 
417 #ifdef notdef
418 unp_abort(unp)
419 	struct unpcb *unp;
420 {
421 
422 	unp_detach(unp);
423 }
424 #endif
425 
426 /*ARGSUSED*/
427 unp_usrclosed(unp)
428 	struct unpcb *unp;
429 {
430 
431 }
432 
433 unp_drop(unp, errno)
434 	struct unpcb *unp;
435 	int errno;
436 {
437 
438 	unp->unp_socket->so_error = errno;
439 	unp_disconnect(unp);
440 }
441 
442 #ifdef notdef
443 unp_drain()
444 {
445 
446 }
447 #endif
448 
449 unp_externalize(rights)
450 	struct mbuf *rights;
451 {
452 	int newfds = rights->m_len / sizeof (int);
453 	register int i;
454 	register struct file **rp = mtod(rights, struct file **);
455 	register struct file *fp;
456 	int f;
457 
458 	if (newfds > ufavail()) {
459 		for (i = 0; i < newfds; i++) {
460 			fp = *rp;
461 			unp_discard(fp);
462 			*rp++ = 0;
463 		}
464 		return (EMSGSIZE);
465 	}
466 	for (i = 0; i < newfds; i++) {
467 		f = ufalloc(0);
468 		if (f < 0)
469 			panic("unp_externalize");
470 		fp = *rp;
471 		u.u_ofile[f] = fp;
472 		fp->f_msgcount--;
473 		*(int *)rp = f;
474 	}
475 	return (0);
476 }
477 
478 unp_internalize(rights)
479 	struct mbuf *rights;
480 {
481 	register struct file **rp;
482 	int oldfds = rights->m_len / sizeof (int);
483 	register int i;
484 	register struct file *fp;
485 
486 	rp = mtod(rights, struct file **);
487 	for (i = 0; i < oldfds; i++)
488 		if (getf(*(int *)rp++) == 0)
489 			return (EBADF);
490 	rp = mtod(rights, struct file **);
491 	for (i = 0; i < oldfds; i++) {
492 		fp = getf(*(int *)rp);
493 		*rp++ = fp;
494 		fp->f_count++;
495 		fp->f_msgcount++;
496 	}
497 	return (0);
498 }
499 
500 int	unp_defer, unp_gcing;
501 int	unp_mark();
502 
503 unp_gc()
504 {
505 	register struct file *fp;
506 	register struct socket *so;
507 
508 	if (unp_gcing)
509 		return;
510 	unp_gcing = 1;
511 restart:
512 	unp_defer = 0;
513 	for (fp = file; fp < fileNFILE; fp++)
514 		fp->f_flag &= ~(FMARK|FDEFER);
515 	do {
516 		for (fp = file; fp < fileNFILE; fp++) {
517 			if (fp->f_count == 0)
518 				continue;
519 			if (fp->f_flag & FDEFER) {
520 				fp->f_flag &= ~FDEFER;
521 				unp_defer--;
522 			} else {
523 				if (fp->f_flag & FMARK)
524 					continue;
525 				if (fp->f_count == fp->f_msgcount)
526 					continue;
527 				fp->f_flag |= FMARK;
528 			}
529 			if (fp->f_type != DTYPE_SOCKET)
530 				continue;
531 			so = (struct socket *)fp->f_data;
532 			if (so->so_proto->pr_family != AF_UNIX ||
533 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
534 				continue;
535 			if (so->so_rcv.sb_flags & SB_LOCK) {
536 				sbwait(&so->so_rcv);
537 				goto restart;
538 			}
539 			unp_scan(so->so_rcv.sb_mb, unp_mark);
540 		}
541 	} while (unp_defer);
542 	for (fp = file; fp < fileNFILE; fp++) {
543 		if (fp->f_count == 0)
544 			continue;
545 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
546 			if (fp->f_type != DTYPE_SOCKET)
547 				panic("unp_gc");
548 			(void) soshutdown((struct socket *)fp->f_data, 0);
549 		}
550 	}
551 	unp_gcing = 0;
552 }
553 
554 unp_scan(m, op)
555 	register struct mbuf *m;
556 	int (*op)();
557 {
558 	register struct file **rp;
559 	register int i;
560 	int qfds;
561 
562 	while (m) {
563 		m = m->m_next;
564 		if (m == 0)
565 			goto bad;
566 		if (m->m_len) {
567 			qfds = m->m_len / sizeof (struct file *);
568 			rp = mtod(m, struct file **);
569 			for (i = 0; i < qfds; i++)
570 				(*op)(*rp++);
571 		}
572 		do {
573 			m = m->m_next;
574 			if (m == 0)
575 				goto bad;
576 		} while (m->m_act == 0);
577 		m = m->m_next;
578 	}
579 	return;
580 bad:
581 	panic("unp_gcscan");
582 }
583 
584 unp_mark(fp)
585 	struct file *fp;
586 {
587 
588 	if (fp->f_flag & FMARK)
589 		return;
590 	unp_defer++;
591 	fp->f_flag |= (FMARK|FDEFER);
592 }
593 
594 unp_discard(fp)
595 	struct file *fp;
596 {
597 
598 	fp->f_msgcount--;
599 	closef(fp);
600 }
601