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