xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 9169)
1*9169Ssam /*	uipc_usrreq.c	1.3	82/11/13	*/
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"
13*9169Ssam #include "../h/nami.h"
148925Sroot 
158925Sroot /*
168925Sroot  * Unix communications domain.
178925Sroot  */
188925Sroot 
198925Sroot /*ARGSUSED*/
209028Sroot uipc_usrreq(so, req, m, nam, opt)
218925Sroot 	struct socket *so;
228925Sroot 	int req;
239028Sroot 	struct mbuf *m, *nam;
249028Sroot 	struct socketopt *opt;
258925Sroot {
268925Sroot 	struct unpcb *unp = sotounpcb(so);
278925Sroot 	register struct socket *so2;
288925Sroot 	int error = 0;
298925Sroot 
308925Sroot 	if (unp == 0 && req != PRU_ATTACH)
318925Sroot 		return (EINVAL);			/* XXX */
328925Sroot 	switch (req) {
338925Sroot 
348925Sroot 	case PRU_ATTACH:
358925Sroot 		if (unp) {
36*9169Ssam 			error = EISCONN;
378925Sroot 			break;
388925Sroot 		}
399028Sroot 		error = unp_attach(so);
408925Sroot 		break;
418925Sroot 
428925Sroot 	case PRU_DETACH:
438925Sroot 		unp_detach(unp);
448925Sroot 		break;
458925Sroot 
46*9169Ssam 	case PRU_BIND:
47*9169Ssam 		error = unp_bind(unp, nam);
48*9169Ssam 		break;
49*9169Ssam 
50*9169Ssam 	case PRU_LISTEN:
51*9169Ssam 		if (unp->unp_inode == 0)
52*9169Ssam 			error = EINVAL;
53*9169Ssam 		break;
54*9169Ssam 
558925Sroot 	case PRU_CONNECT:
569028Sroot 		error = unp_connect(so, nam);
578925Sroot 		break;
588925Sroot 
598925Sroot 	case PRU_DISCONNECT:
608925Sroot 		unp_disconnect(unp);
618925Sroot 		break;
628925Sroot 
63*9169Ssam 	case PRU_ACCEPT:
64*9169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
65*9169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
66*9169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
678925Sroot 		break;
688925Sroot 
698925Sroot 	case PRU_SHUTDOWN:
708925Sroot 		socantsendmore(so);
718925Sroot 		unp_usrclosed(unp);
728925Sroot 		break;
738925Sroot 
748925Sroot 	case PRU_RCVD:
758925Sroot 		switch (so->so_type) {
768925Sroot 
778925Sroot 		case SOCK_DGRAM:
788925Sroot 			panic("uipc 1");
798925Sroot 
808925Sroot 		case SOCK_STREAM: {
818925Sroot #define	rcv (&so->so_rcv)
828925Sroot #define snd (&so2->so_snd)
838925Sroot 			if (unp->unp_conn == 0)
848925Sroot 				break;
858925Sroot 			so2 = unp->unp_conn->unp_socket;
868925Sroot 			/*
878925Sroot 			 * Transfer resources back to send port
888925Sroot 			 * and wakeup any waiting to write.
898925Sroot 			 */
908925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
918925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
928925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
938925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
948925Sroot 			sbwakeup(snd);
958925Sroot #undef snd
968925Sroot #undef rcv
978925Sroot 			}
988925Sroot 			break;
998925Sroot 
1008925Sroot 		default:
1018925Sroot 			panic("uipc 2");
1028925Sroot 		}
1038925Sroot 		break;
1048925Sroot 
1058925Sroot 	case PRU_SEND:
1068925Sroot 		switch (so->so_type) {
1078925Sroot 
1088925Sroot 		case SOCK_DGRAM:
1099028Sroot 			if (nam) {
1108925Sroot 				if (unp->unp_conn) {
1118925Sroot 					error = EISCONN;
1128925Sroot 					break;
1138925Sroot 				}
1149028Sroot 				error = unp_connect(so, nam);
1158925Sroot 				if (error)
1168925Sroot 					break;
1178925Sroot 			} else {
1188925Sroot 				if (unp->unp_conn == 0) {
1198925Sroot 					error = ENOTCONN;
1208925Sroot 					break;
1218925Sroot 				}
1228925Sroot 			}
1238925Sroot 			so2 = unp->unp_conn->unp_socket;
124*9169Ssam 			/* BEGIN XXX */
125*9169Ssam 			if (sbspace(&so2->so_rcv) > 0)
126*9169Ssam 				(void) sbappendaddr(&so2->so_rcv,
127*9169Ssam 					mtod(nam, struct sockaddr *), m);
128*9169Ssam 			/* END XXX */
1299028Sroot 			if (nam)
130*9169Ssam 				unp_disconnect(unp);
1318925Sroot 			break;
1328925Sroot 
1338925Sroot 		case SOCK_STREAM:
1348925Sroot #define	rcv (&so2->so_rcv)
1358925Sroot #define	snd (&so->so_snd)
1368925Sroot 			if (unp->unp_conn == 0)
1378925Sroot 				panic("uipc 3");
1388925Sroot 			so2 = unp->unp_conn->unp_socket;
1398925Sroot 			/*
1408925Sroot 			 * Send to paired receive port, and then
1418925Sroot 			 * give it enough resources to hold what it already has.
1428925Sroot 			 * Wake up readers.
1438925Sroot 			 */
1448925Sroot 			sbappend(rcv, m);
1458925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1468925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1478925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1488925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1498925Sroot 			sbwakeup(rcv);
1508925Sroot #undef snd
1518925Sroot #undef rcv
1528925Sroot 			break;
1538925Sroot 
1548925Sroot 		default:
1558925Sroot 			panic("uipc 4");
1568925Sroot 		}
1578925Sroot 		break;
1588925Sroot 
1598925Sroot 	case PRU_ABORT:
1608925Sroot 		unp_drop(unp, ECONNABORTED);
1618925Sroot 		break;
1628925Sroot 
1638925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
1648925Sroot 	case PRU_CONTROL:
1658925Sroot 		error = EOPNOTSUPP;
1668925Sroot 		break;
1678925Sroot 
1688925Sroot 	case PRU_SENSE:
1698925Sroot 		error = EOPNOTSUPP;
1708925Sroot 		break;
1718925Sroot /* END UNIMPLEMENTED HOOKS */
1728925Sroot 
1738925Sroot 	case PRU_RCVOOB:
1748925Sroot 		break;
1758925Sroot 
1768925Sroot 	case PRU_SENDOOB:
1778925Sroot 		break;
1788925Sroot 
1798925Sroot 	case PRU_SOCKADDR:
1808925Sroot 		break;
1818925Sroot 
1828925Sroot 	case PRU_SLOWTIMO:
1838925Sroot 		break;
1848925Sroot 
1858925Sroot 	default:
1868925Sroot 		panic("piusrreq");
1878925Sroot 	}
1888925Sroot 	return (0);
1898925Sroot }
1908925Sroot 
1918925Sroot int	unp_sendspace = 1024*2;
1928925Sroot int	unp_recvspace = 1024*2;
1938925Sroot 
194*9169Ssam unp_attach(so)
1958925Sroot 	struct socket *so;
1968925Sroot {
197*9169Ssam 	register struct mbuf *m;
1988925Sroot 	register struct unpcb *unp;
1998925Sroot 	int error;
2008925Sroot 
2018925Sroot 	error = soreserve(so, unp_sendspace, unp_recvspace);
2028925Sroot 	if (error)
2038925Sroot 		goto bad;
2048925Sroot 	m = m_getclr(M_DONTWAIT);
2058925Sroot 	if (m == 0) {
2068925Sroot 		error = ENOBUFS;
2078925Sroot 		goto bad;
2088925Sroot 	}
2098925Sroot 	unp = mtod(m, struct unpcb *);
2108925Sroot 	so->so_pcb = (caddr_t)unp;
2118925Sroot 	unp->unp_socket = so;
2128925Sroot 	return (0);
2138925Sroot bad:
2148925Sroot 	return (error);
2158925Sroot }
2168925Sroot 
2178925Sroot unp_detach(unp)
218*9169Ssam 	register struct unpcb *unp;
2198925Sroot {
2208925Sroot 
2218925Sroot 	if (unp->unp_inode) {
2228925Sroot 		irele(unp->unp_inode);
2238925Sroot 		unp->unp_inode = 0;
2248925Sroot 	}
2258925Sroot 	if (unp->unp_conn)
2268925Sroot 		unp_disconnect(unp);
2278925Sroot 	while (unp->unp_refs)
2288925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2298925Sroot 	soisdisconnected(unp->unp_socket);
2308925Sroot 	unp->unp_socket->so_pcb = 0;
231*9169Ssam 	m_freem(unp->unp_remaddr);
232*9169Ssam 	(void) m_free(dtom(unp));
2338925Sroot }
2348925Sroot 
235*9169Ssam unp_bind(unp, nam)
2368925Sroot 	struct unpcb *unp;
237*9169Ssam 	struct mbuf *nam;
2388925Sroot {
239*9169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
2408925Sroot 	register struct inode *ip;
241*9169Ssam 	extern schar();
2428925Sroot 	int error;
2438925Sroot 
2448925Sroot 	u.u_dirp = soun->sun_path;
2458925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
246*9169Ssam 	ip = namei(schar, CREATE, 1);
2478925Sroot 	if (ip) {
2488925Sroot 		iput(ip);
2498925Sroot 		return (EEXIST);
2508925Sroot 	}
2518925Sroot 	ip = maknode(IFSOCK | 0777);
2528925Sroot 	if (ip == NULL) {
2538925Sroot 		error = u.u_error;		/* XXX */
2548925Sroot 		u.u_error = 0;			/* XXX */
2558925Sroot 		return (error);
2568925Sroot 	}
2578925Sroot 	ip->i_socket = unp->unp_socket;
2588925Sroot 	unp->unp_inode = ip;
2598925Sroot 	iunlock(ip);			/* but keep reference */
2608925Sroot 	return (0);
2618925Sroot }
2628925Sroot 
263*9169Ssam unp_connect(so, nam)
2648925Sroot 	struct socket *so;
265*9169Ssam 	struct mbuf *nam;
2668925Sroot {
267*9169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
268*9169Ssam 	struct unpcb *unp = sotounpcb(so);
269*9169Ssam 	register struct inode *ip;
2708925Sroot 	int error;
271*9169Ssam 	struct socket *so2;
272*9169Ssam 	struct unpcb *unp2;
2738925Sroot 
2748925Sroot 	u.u_dirp = soun->sun_path;
2758925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
276*9169Ssam 	ip = namei(schar, LOOKUP, 1);
2778925Sroot 	if (ip == 0) {
2788925Sroot 		error = u.u_error;
2798925Sroot 		u.u_error = 0;
2808925Sroot 		return (ENOENT);
2818925Sroot 	}
2828925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
2838925Sroot 		error = ENOTSOCK;
2848925Sroot 		goto bad;
2858925Sroot 	}
2868925Sroot 	so2 = ip->i_socket;
2878925Sroot 	if (so2 == 0) {
2888925Sroot 		error = ECONNREFUSED;
2898925Sroot 		goto bad;
2908925Sroot 	}
2918925Sroot 	if (so2->so_type != so->so_type) {
2928925Sroot 		error = EPROTOTYPE;
2938925Sroot 		goto bad;
2948925Sroot 	}
2958925Sroot 	switch (so->so_type) {
2968925Sroot 
2978925Sroot 	case SOCK_DGRAM:
2988925Sroot 		unp->unp_conn = sotounpcb(so2);
2998925Sroot 		unp2 = sotounpcb(so2);
3008925Sroot 		unp->unp_nextref = unp2->unp_refs;
3018925Sroot 		unp2->unp_refs = unp;
3028925Sroot 		break;
3038925Sroot 
3048925Sroot 	case SOCK_STREAM:
3058925Sroot 		if ((so2->so_options&SO_ACCEPTCONN) == 0 ||
306*9169Ssam 		    (so2 = sonewconn(so2)) == 0) {
3078925Sroot 			error = ECONNREFUSED;
3088925Sroot 			goto bad;
3098925Sroot 		}
310*9169Ssam 		unp2 = sotounpcb(so2);
311*9169Ssam 		unp->unp_conn = unp2;
312*9169Ssam 		unp2->unp_conn = unp;
313*9169Ssam 		unp2->unp_remaddr = m_copy(nam, 0, (int)M_COPYALL);
3148925Sroot 		break;
3158925Sroot 
3168925Sroot 	default:
3178925Sroot 		panic("uipc connip");
3188925Sroot 	}
319*9169Ssam 	soisconnected(so2);
3208925Sroot 	soisconnected(so);
3218925Sroot 	iput(ip);
3228925Sroot 	return (0);
3238925Sroot bad:
3248925Sroot 	iput(ip);
3258925Sroot 	return (error);
3268925Sroot }
327*9169Ssam 
328*9169Ssam unp_disconnect(unp)
329*9169Ssam 	struct unpcb *unp;
330*9169Ssam {
331*9169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
332*9169Ssam 
333*9169Ssam 	if (unp2 == 0)
334*9169Ssam 		return;
335*9169Ssam 	unp->unp_conn = 0;
336*9169Ssam 	soisdisconnected(unp->unp_socket);
337*9169Ssam 	switch (unp->unp_socket->so_type) {
338*9169Ssam 
339*9169Ssam 	case SOCK_DGRAM:
340*9169Ssam 		if (unp2->unp_refs == unp)
341*9169Ssam 			unp2->unp_refs = unp->unp_nextref;
342*9169Ssam 		else {
343*9169Ssam 			unp2 = unp2->unp_refs;
344*9169Ssam 			for (;;) {
345*9169Ssam 				if (unp2 == 0)
346*9169Ssam 					panic("unp_disconnect");
347*9169Ssam 				if (unp2->unp_nextref == unp)
348*9169Ssam 					break;
349*9169Ssam 				unp2 = unp2->unp_nextref;
350*9169Ssam 			}
351*9169Ssam 			unp2->unp_nextref = unp->unp_nextref;
352*9169Ssam 		}
353*9169Ssam 		unp->unp_nextref = 0;
354*9169Ssam 		break;
355*9169Ssam 
356*9169Ssam 	case SOCK_STREAM:
357*9169Ssam 		unp2->unp_conn = 0;
358*9169Ssam 		soisdisconnected(unp2->unp_socket);
359*9169Ssam 		unp_drop(unp2, ECONNRESET);
360*9169Ssam 		break;
361*9169Ssam 	}
362*9169Ssam }
363*9169Ssam 
364*9169Ssam unp_abort(unp)
365*9169Ssam 	struct unpcb *unp;
366*9169Ssam {
367*9169Ssam 
368*9169Ssam 	unp_detach(unp);
369*9169Ssam }
370*9169Ssam 
371*9169Ssam /*ARGSUSED*/
372*9169Ssam unp_usrclosed(unp)
373*9169Ssam 	struct unpcb *unp;
374*9169Ssam {
375*9169Ssam 
376*9169Ssam }
377*9169Ssam 
378*9169Ssam unp_drop(unp, errno)
379*9169Ssam 	struct unpcb *unp;
380*9169Ssam 	int errno;
381*9169Ssam {
382*9169Ssam 
383*9169Ssam 	unp->unp_socket->so_error = errno;
384*9169Ssam 	unp_disconnect(unp);
385*9169Ssam }
386*9169Ssam 
387*9169Ssam unp_drain()
388*9169Ssam {
389*9169Ssam 
390*9169Ssam }
391