xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 9028)
1*9028Sroot /*	uipc_usrreq.c	1.2	82/11/03	*/
28925Sroot 
38925Sroot #include "../h/param.h"
48925Sroot #include "../h/dir.h"
58925Sroot #include "../h/user.h"
68925Sroot #include "../h/mbuf.h"
78925Sroot #include "../h/protosw.h"
88925Sroot #include "../h/socket.h"
98925Sroot #include "../h/socketvar.h"
108925Sroot #include "../h/unpcb.h"
118925Sroot #include "../h/un.h"
128925Sroot #include "../h/inode.h"
138925Sroot 
148925Sroot /*
158925Sroot  * Unix communications domain.
168925Sroot  */
178925Sroot 
188925Sroot /*ARGSUSED*/
19*9028Sroot uipc_usrreq(so, req, m, nam, opt)
208925Sroot 	struct socket *so;
218925Sroot 	int req;
22*9028Sroot 	struct mbuf *m, *nam;
23*9028Sroot 	struct socketopt *opt;
248925Sroot {
258925Sroot 	struct unpcb *unp = sotounpcb(so);
268925Sroot 	register struct socket *so2;
278925Sroot 	int error = 0;
288925Sroot 
298925Sroot 	if (unp == 0 && req != PRU_ATTACH)
308925Sroot 		return (EINVAL);			/* XXX */
318925Sroot 	switch (req) {
328925Sroot 
338925Sroot 	case PRU_ATTACH:
348925Sroot 		if (unp) {
358925Sroot 			error = EINVAL;
368925Sroot 			break;
378925Sroot 		}
38*9028Sroot 		error = unp_attach(so);
398925Sroot 		break;
408925Sroot 
418925Sroot 	case PRU_DETACH:
428925Sroot 		unp_detach(unp);
438925Sroot 		break;
448925Sroot 
458925Sroot 	case PRU_CONNECT:
46*9028Sroot 		error = unp_connect(so, nam);
478925Sroot 		break;
488925Sroot 
498925Sroot 	case PRU_DISCONNECT:
508925Sroot 		unp_disconnect(unp);
518925Sroot 		break;
528925Sroot 
538925Sroot /* BEGIN QUESTIONABLE */
548925Sroot 	case PRU_ACCEPT: {
55*9028Sroot 		struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
568925Sroot 
578925Sroot 		if (soun) {
588925Sroot 			bzero((caddr_t)soun, sizeof (*soun));
598925Sroot 			soun->sun_family = AF_UNIX;
608925Sroot 			/* XXX */
618925Sroot 		}
628925Sroot 		}
638925Sroot 		break;
648925Sroot 
658925Sroot 	case PRU_SHUTDOWN:
668925Sroot 		socantsendmore(so);
678925Sroot 		unp_usrclosed(unp);
688925Sroot 		break;
698925Sroot /* END QUESTIONABLE */
708925Sroot 
718925Sroot 	case PRU_RCVD:
728925Sroot 		switch (so->so_type) {
738925Sroot 
748925Sroot 		case SOCK_DGRAM:
758925Sroot 			panic("uipc 1");
768925Sroot 
778925Sroot 		case SOCK_STREAM: {
788925Sroot #define	rcv (&so->so_rcv)
798925Sroot #define snd (&so2->so_snd)
808925Sroot 			if (unp->unp_conn == 0)
818925Sroot 				break;
828925Sroot 			so2 = unp->unp_conn->unp_socket;
838925Sroot 			/*
848925Sroot 			 * Transfer resources back to send port
858925Sroot 			 * and wakeup any waiting to write.
868925Sroot 			 */
878925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
888925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
898925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
908925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
918925Sroot 			sbwakeup(snd);
928925Sroot #undef snd
938925Sroot #undef rcv
948925Sroot 			}
958925Sroot 			break;
968925Sroot 
978925Sroot 		default:
988925Sroot 			panic("uipc 2");
998925Sroot 		}
1008925Sroot 		break;
1018925Sroot 
1028925Sroot 	case PRU_SEND:
1038925Sroot 		switch (so->so_type) {
1048925Sroot 
1058925Sroot 		case SOCK_DGRAM:
106*9028Sroot 			if (nam) {
1078925Sroot 				if (unp->unp_conn) {
1088925Sroot 					error = EISCONN;
1098925Sroot 					break;
1108925Sroot 				}
111*9028Sroot 				error = unp_connect(so, nam);
1128925Sroot 				if (error)
1138925Sroot 					break;
1148925Sroot 			} else {
1158925Sroot 				if (unp->unp_conn == 0) {
1168925Sroot 					error = ENOTCONN;
1178925Sroot 					break;
1188925Sroot 				}
1198925Sroot 			}
1208925Sroot 			so2 = unp->unp_conn->unp_socket;
1218925Sroot 			if (sbspace(&so2->so_rcv) > 0)		/* XXX */
122*9028Sroot 				sbappendaddr(so2, m, nam);	/* XXX */
123*9028Sroot 			if (nam)
1248925Sroot 				unp_disconnect(so);
1258925Sroot 			break;
1268925Sroot 
1278925Sroot 		case SOCK_STREAM:
1288925Sroot #define	rcv (&so2->so_rcv)
1298925Sroot #define	snd (&so->so_snd)
1308925Sroot 			if (unp->unp_conn == 0)
1318925Sroot 				panic("uipc 3");
1328925Sroot 			so2 = unp->unp_conn->unp_socket;
1338925Sroot 			/*
1348925Sroot 			 * Send to paired receive port, and then
1358925Sroot 			 * give it enough resources to hold what it already has.
1368925Sroot 			 * Wake up readers.
1378925Sroot 			 */
1388925Sroot 			sbappend(rcv, m);
1398925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1408925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1418925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1428925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1438925Sroot 			sbwakeup(rcv);
1448925Sroot #undef snd
1458925Sroot #undef rcv
1468925Sroot 			break;
1478925Sroot 
1488925Sroot 		default:
1498925Sroot 			panic("uipc 4");
1508925Sroot 		}
1518925Sroot 		break;
1528925Sroot 
1538925Sroot 	case PRU_ABORT:
1548925Sroot 		unp_drop(unp, ECONNABORTED);
1558925Sroot 		break;
1568925Sroot 
1578925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
1588925Sroot 	case PRU_CONTROL:
1598925Sroot 		error = EOPNOTSUPP;
1608925Sroot 		break;
1618925Sroot 
1628925Sroot 	case PRU_SENSE:
1638925Sroot 		error = EOPNOTSUPP;
1648925Sroot 		break;
1658925Sroot /* END UNIMPLEMENTED HOOKS */
1668925Sroot 
1678925Sroot 	case PRU_RCVOOB:
1688925Sroot 		break;
1698925Sroot 
1708925Sroot 	case PRU_SENDOOB:
1718925Sroot 		break;
1728925Sroot 
1738925Sroot 	case PRU_SOCKADDR:
1748925Sroot 		break;
1758925Sroot 
1768925Sroot 	case PRU_SLOWTIMO:
1778925Sroot 		break;
1788925Sroot 
1798925Sroot 	default:
1808925Sroot 		panic("piusrreq");
1818925Sroot 	}
1828925Sroot 	return (0);
1838925Sroot }
1848925Sroot 
1858925Sroot int	unp_sendspace = 1024*2;
1868925Sroot int	unp_recvspace = 1024*2;
1878925Sroot 
1888925Sroot unp_attach(so, soun)
1898925Sroot 	struct socket *so;
1908925Sroot 	struct sockaddr_un *soun;
1918925Sroot {
1928925Sroot 	register struct unpcb *unp;
1938925Sroot 	struct mbuf *m;
1948925Sroot 	int error;
1958925Sroot 
1968925Sroot 	error = soreserve(so, unp_sendspace, unp_recvspace);
1978925Sroot 	if (error)
1988925Sroot 		goto bad;
1998925Sroot 	m = m_getclr(M_DONTWAIT);
2008925Sroot 	if (m == 0) {
2018925Sroot 		error = ENOBUFS;
2028925Sroot 		goto bad;
2038925Sroot 	}
2048925Sroot 	unp = mtod(m, struct unpcb *);
2058925Sroot 	so->so_pcb = (caddr_t)unp;
2068925Sroot 	unp->unp_socket = so;
2078925Sroot 	if (soun) {
2088925Sroot 		error = unp_bind(unp, soun);
2098925Sroot 		if (error) {
2108925Sroot 			unp_detach(unp);
2118925Sroot 			goto bad;
2128925Sroot 		}
2138925Sroot 	}
2148925Sroot 	return (0);
2158925Sroot bad:
2168925Sroot 	return (error);
2178925Sroot }
2188925Sroot 
2198925Sroot unp_disconnect(unp)
2208925Sroot 	struct unpcb *unp;
2218925Sroot {
2228925Sroot 	register struct unpcb *unp2 = unp->unp_conn;
2238925Sroot 
2248925Sroot 	if (unp2 == 0)
2258925Sroot 		return;
2268925Sroot 	unp->unp_conn = 0;
2278925Sroot 	soisdisconnected(unp->unp_socket);
2288925Sroot 	switch (unp->unp_socket->so_type) {
2298925Sroot 
2308925Sroot 	case SOCK_DGRAM:
2318925Sroot 		if (unp2->unp_refs == unp)
2328925Sroot 			unp2->unp_refs = unp->unp_nextref;
2338925Sroot 		else {
2348925Sroot 			unp2 = unp2->unp_refs;
2358925Sroot 			for (;;) {
2368925Sroot 				if (unp2 == 0)
2378925Sroot 					panic("unp_disconnect");
2388925Sroot 				if (unp2->unp_nextref == unp)
2398925Sroot 					break;
2408925Sroot 				unp2 = unp2->unp_nextref;
2418925Sroot 			}
2428925Sroot 			unp2->unp_nextref = unp->unp_nextref;
2438925Sroot 		}
2448925Sroot 		unp->unp_nextref = 0;
2458925Sroot 		break;
2468925Sroot 
2478925Sroot 	case SOCK_STREAM:
2488925Sroot 		unp2->unp_conn = 0;
2498925Sroot 		soisdisconnected(unp2->unp_socket);
2508925Sroot 		unp_drop(unp2, ECONNRESET);
2518925Sroot 		break;
2528925Sroot 	}
2538925Sroot }
2548925Sroot 
2558925Sroot unp_abort(unp)
2568925Sroot 	struct unpcb *unp;
2578925Sroot {
2588925Sroot 
2598925Sroot 	unp_detach(unp);
2608925Sroot }
2618925Sroot 
2628925Sroot unp_detach(unp)
2638925Sroot 	struct unpcb *unp;
2648925Sroot {
2658925Sroot 
2668925Sroot 	if (unp->unp_inode) {
2678925Sroot 		irele(unp->unp_inode);
2688925Sroot 		unp->unp_inode = 0;
2698925Sroot 	}
2708925Sroot 	if (unp->unp_conn)
2718925Sroot 		unp_disconnect(unp);
2728925Sroot 	while (unp->unp_refs)
2738925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2748925Sroot 	soisdisconnected(unp->unp_socket);
2758925Sroot 	unp->unp_socket->so_pcb = 0;
2768925Sroot 	m_free(dtom(unp));
2778925Sroot }
2788925Sroot 
2798925Sroot unp_usrclosed(unp)
2808925Sroot 	struct unpcb *unp;
2818925Sroot {
2828925Sroot 	register struct socket *so = unp->unp_socket;
2838925Sroot 
2848925Sroot #ifdef sometimes /* ??? */
2858925Sroot 	soisdisconnected(unp->unp_socket);
2868925Sroot #endif
2878925Sroot }
2888925Sroot 
2898925Sroot unp_drop(unp, errno)
2908925Sroot 	struct unpcb *unp;
2918925Sroot 	int errno;
2928925Sroot {
2938925Sroot 
2948925Sroot 	unp->unp_socket->so_error = errno;
2958925Sroot 	unp_disconnect(unp);
2968925Sroot }
2978925Sroot 
2988925Sroot unp_drain()
2998925Sroot {
3008925Sroot 
3018925Sroot }
3028925Sroot 
3038925Sroot unp_bind(unp, soun)
3048925Sroot 	struct unpcb *unp;
3058925Sroot 	struct sockaddr_un *soun;
3068925Sroot {
3078925Sroot 	register struct inode *ip;
3088925Sroot 	int error;
3098925Sroot 	extern schar();
3108925Sroot 
3118925Sroot 	u.u_dirp = soun->sun_path;
3128925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
3138925Sroot 	ip = namei(schar, 1, 1);
3148925Sroot 	if (ip) {
3158925Sroot 		iput(ip);
3168925Sroot 		return (EEXIST);
3178925Sroot 	}
3188925Sroot 	ip = maknode(IFSOCK | 0777);
3198925Sroot 	if (ip == NULL) {
3208925Sroot 		error = u.u_error;		/* XXX */
3218925Sroot 		u.u_error = 0;			/* XXX */
3228925Sroot 		return (error);
3238925Sroot 	}
3248925Sroot 	ip->i_socket = unp->unp_socket;
3258925Sroot 	unp->unp_inode = ip;
3268925Sroot 	iunlock(ip);			/* but keep reference */
3278925Sroot 	return (0);
3288925Sroot }
3298925Sroot 
3308925Sroot unp_connect(so, soun)
3318925Sroot 	struct socket *so;
3328925Sroot 	struct sockaddr_un *soun;
3338925Sroot {
3348925Sroot 	struct inode *ip;
3358925Sroot 	int error;
3368925Sroot 
3378925Sroot 	u.u_dirp = soun->sun_path;
3388925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
3398925Sroot 	ip = namei(schar, 0, 1);
3408925Sroot 	if (ip == 0) {
3418925Sroot 		error = u.u_error;
3428925Sroot 		u.u_error = 0;
3438925Sroot 		return (ENOENT);
3448925Sroot 	}
3458925Sroot 	error = unp_connectip(so, ip);
3468925Sroot 	return (error);
3478925Sroot }
3488925Sroot 
3498925Sroot unp_connectip(so, ip)
3508925Sroot 	struct socket *so;
3518925Sroot 	struct inode *ip;
3528925Sroot {
3538925Sroot 	struct unpcb *unp = sotounpcb(so);
3548925Sroot 	struct socket *so2, *so3;
3558925Sroot 	int error;
3568925Sroot 	struct unpcb *unp2;
3578925Sroot 
3588925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3598925Sroot 		error = ENOTSOCK;
3608925Sroot 		goto bad;
3618925Sroot 	}
3628925Sroot 	so2 = ip->i_socket;
3638925Sroot 	if (so2 == 0) {
3648925Sroot 		error = ECONNREFUSED;
3658925Sroot 		goto bad;
3668925Sroot 	}
3678925Sroot 	if (so2->so_type != so->so_type) {
3688925Sroot 		error = EPROTOTYPE;
3698925Sroot 		goto bad;
3708925Sroot 	}
3718925Sroot 	switch (so->so_type) {
3728925Sroot 
3738925Sroot 	case SOCK_DGRAM:
3748925Sroot 		unp->unp_conn = sotounpcb(so2);
3758925Sroot 		unp2 = sotounpcb(so2);
3768925Sroot 		unp->unp_nextref = unp2->unp_refs;
3778925Sroot 		unp2->unp_refs = unp;
3788925Sroot 		break;
3798925Sroot 
3808925Sroot 	case SOCK_STREAM:
3818925Sroot 		if ((so2->so_options&SO_ACCEPTCONN) == 0 ||
3828925Sroot 		    (so3 = sonewconn(so2)) == 0) {
3838925Sroot 			error = ECONNREFUSED;
3848925Sroot 			goto bad;
3858925Sroot 		}
3868925Sroot 		unp->unp_conn = sotounpcb(so3);
3878925Sroot 		break;
3888925Sroot 
3898925Sroot 	default:
3908925Sroot 		panic("uipc connip");
3918925Sroot 	}
3928925Sroot 	soisconnected(unp->unp_conn->unp_socket);
3938925Sroot 	soisconnected(so);
3948925Sroot 	iput(ip);
3958925Sroot 	return (0);
3968925Sroot bad:
3978925Sroot 	iput(ip);
3988925Sroot 	return (error);
3998925Sroot }
400