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