xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 8925)
1*8925Sroot /*	uipc_usrreq.c	1.1	82/10/28	*/
2*8925Sroot 
3*8925Sroot #include "../h/param.h"
4*8925Sroot #include "../h/dir.h"
5*8925Sroot #include "../h/user.h"
6*8925Sroot #include "../h/mbuf.h"
7*8925Sroot #include "../h/protosw.h"
8*8925Sroot #include "../h/socket.h"
9*8925Sroot #include "../h/socketvar.h"
10*8925Sroot #include "../h/unpcb.h"
11*8925Sroot #include "../h/un.h"
12*8925Sroot #include "../h/inode.h"
13*8925Sroot 
14*8925Sroot /*
15*8925Sroot  * Unix communications domain.
16*8925Sroot  */
17*8925Sroot 
18*8925Sroot /*ARGSUSED*/
19*8925Sroot uipc_usrreq(so, req, m, addr)
20*8925Sroot 	struct socket *so;
21*8925Sroot 	int req;
22*8925Sroot 	struct mbuf *m;
23*8925Sroot 	caddr_t addr;
24*8925Sroot {
25*8925Sroot 	struct unpcb *unp = sotounpcb(so);
26*8925Sroot 	register struct socket *so2;
27*8925Sroot 	int error = 0;
28*8925Sroot 
29*8925Sroot 	if (unp == 0 && req != PRU_ATTACH)
30*8925Sroot 		return (EINVAL);			/* XXX */
31*8925Sroot 	switch (req) {
32*8925Sroot 
33*8925Sroot 	case PRU_ATTACH:
34*8925Sroot 		if (unp) {
35*8925Sroot 			error = EINVAL;
36*8925Sroot 			break;
37*8925Sroot 		}
38*8925Sroot 		error = unp_attach(so, (struct sockaddr *)addr);
39*8925Sroot 		break;
40*8925Sroot 
41*8925Sroot 	case PRU_DETACH:
42*8925Sroot 		unp_detach(unp);
43*8925Sroot 		break;
44*8925Sroot 
45*8925Sroot 	case PRU_CONNECT:
46*8925Sroot 		error = unp_connect(so, (struct sockaddr_un *)addr);
47*8925Sroot 		break;
48*8925Sroot 
49*8925Sroot 	case PRU_DISCONNECT:
50*8925Sroot 		unp_disconnect(unp);
51*8925Sroot 		break;
52*8925Sroot 
53*8925Sroot /* BEGIN QUESTIONABLE */
54*8925Sroot 	case PRU_ACCEPT: {
55*8925Sroot 		struct sockaddr_un *soun = (struct sockaddr_un *)addr;
56*8925Sroot 
57*8925Sroot 		if (soun) {
58*8925Sroot 			bzero((caddr_t)soun, sizeof (*soun));
59*8925Sroot 			soun->sun_family = AF_UNIX;
60*8925Sroot 			/* XXX */
61*8925Sroot 		}
62*8925Sroot 		}
63*8925Sroot 		break;
64*8925Sroot 
65*8925Sroot 	case PRU_SHUTDOWN:
66*8925Sroot 		socantsendmore(so);
67*8925Sroot 		unp_usrclosed(unp);
68*8925Sroot 		break;
69*8925Sroot /* END QUESTIONABLE */
70*8925Sroot 
71*8925Sroot 	case PRU_RCVD:
72*8925Sroot 		switch (so->so_type) {
73*8925Sroot 
74*8925Sroot 		case SOCK_DGRAM:
75*8925Sroot 			panic("uipc 1");
76*8925Sroot 
77*8925Sroot 		case SOCK_STREAM: {
78*8925Sroot #define	rcv (&so->so_rcv)
79*8925Sroot #define snd (&so2->so_snd)
80*8925Sroot 			if (unp->unp_conn == 0)
81*8925Sroot 				break;
82*8925Sroot 			so2 = unp->unp_conn->unp_socket;
83*8925Sroot 			/*
84*8925Sroot 			 * Transfer resources back to send port
85*8925Sroot 			 * and wakeup any waiting to write.
86*8925Sroot 			 */
87*8925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
88*8925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
89*8925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
90*8925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
91*8925Sroot 			sbwakeup(snd);
92*8925Sroot #undef snd
93*8925Sroot #undef rcv
94*8925Sroot 			}
95*8925Sroot 			break;
96*8925Sroot 
97*8925Sroot 		default:
98*8925Sroot 			panic("uipc 2");
99*8925Sroot 		}
100*8925Sroot 		break;
101*8925Sroot 
102*8925Sroot 	case PRU_SEND:
103*8925Sroot 		switch (so->so_type) {
104*8925Sroot 
105*8925Sroot 		case SOCK_DGRAM:
106*8925Sroot 			if (addr) {
107*8925Sroot 				if (unp->unp_conn) {
108*8925Sroot 					error = EISCONN;
109*8925Sroot 					break;
110*8925Sroot 				}
111*8925Sroot 				error = unp_connect(so, addr);
112*8925Sroot 				if (error)
113*8925Sroot 					break;
114*8925Sroot 			} else {
115*8925Sroot 				if (unp->unp_conn == 0) {
116*8925Sroot 					error = ENOTCONN;
117*8925Sroot 					break;
118*8925Sroot 				}
119*8925Sroot 			}
120*8925Sroot 			so2 = unp->unp_conn->unp_socket;
121*8925Sroot 			if (sbspace(&so2->so_rcv) > 0)		/* XXX */
122*8925Sroot 				sbappendaddr(so2, m, addr);	/* XXX */
123*8925Sroot 			if (addr)
124*8925Sroot 				unp_disconnect(so);
125*8925Sroot 			break;
126*8925Sroot 
127*8925Sroot 		case SOCK_STREAM:
128*8925Sroot #define	rcv (&so2->so_rcv)
129*8925Sroot #define	snd (&so->so_snd)
130*8925Sroot 			if (unp->unp_conn == 0)
131*8925Sroot 				panic("uipc 3");
132*8925Sroot 			so2 = unp->unp_conn->unp_socket;
133*8925Sroot 			/*
134*8925Sroot 			 * Send to paired receive port, and then
135*8925Sroot 			 * give it enough resources to hold what it already has.
136*8925Sroot 			 * Wake up readers.
137*8925Sroot 			 */
138*8925Sroot 			sbappend(rcv, m);
139*8925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
140*8925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
141*8925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
142*8925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
143*8925Sroot 			sbwakeup(rcv);
144*8925Sroot #undef snd
145*8925Sroot #undef rcv
146*8925Sroot 			break;
147*8925Sroot 
148*8925Sroot 		default:
149*8925Sroot 			panic("uipc 4");
150*8925Sroot 		}
151*8925Sroot 		break;
152*8925Sroot 
153*8925Sroot 	case PRU_ABORT:
154*8925Sroot 		unp_drop(unp, ECONNABORTED);
155*8925Sroot 		break;
156*8925Sroot 
157*8925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
158*8925Sroot 	case PRU_CONTROL:
159*8925Sroot 		error = EOPNOTSUPP;
160*8925Sroot 		break;
161*8925Sroot 
162*8925Sroot 	case PRU_SENSE:
163*8925Sroot 		error = EOPNOTSUPP;
164*8925Sroot 		break;
165*8925Sroot /* END UNIMPLEMENTED HOOKS */
166*8925Sroot 
167*8925Sroot 	case PRU_RCVOOB:
168*8925Sroot 		break;
169*8925Sroot 
170*8925Sroot 	case PRU_SENDOOB:
171*8925Sroot 		break;
172*8925Sroot 
173*8925Sroot 	case PRU_SOCKADDR:
174*8925Sroot 		break;
175*8925Sroot 
176*8925Sroot 	case PRU_SLOWTIMO:
177*8925Sroot 		break;
178*8925Sroot 
179*8925Sroot 	default:
180*8925Sroot 		panic("piusrreq");
181*8925Sroot 	}
182*8925Sroot 	return (0);
183*8925Sroot }
184*8925Sroot 
185*8925Sroot int	unp_sendspace = 1024*2;
186*8925Sroot int	unp_recvspace = 1024*2;
187*8925Sroot 
188*8925Sroot unp_attach(so, soun)
189*8925Sroot 	struct socket *so;
190*8925Sroot 	struct sockaddr_un *soun;
191*8925Sroot {
192*8925Sroot 	register struct unpcb *unp;
193*8925Sroot 	struct mbuf *m;
194*8925Sroot 	int error;
195*8925Sroot 
196*8925Sroot 	error = soreserve(so, unp_sendspace, unp_recvspace);
197*8925Sroot 	if (error)
198*8925Sroot 		goto bad;
199*8925Sroot 	m = m_getclr(M_DONTWAIT);
200*8925Sroot 	if (m == 0) {
201*8925Sroot 		error = ENOBUFS;
202*8925Sroot 		goto bad;
203*8925Sroot 	}
204*8925Sroot 	unp = mtod(m, struct unpcb *);
205*8925Sroot 	so->so_pcb = (caddr_t)unp;
206*8925Sroot 	unp->unp_socket = so;
207*8925Sroot 	if (soun) {
208*8925Sroot 		error = unp_bind(unp, soun);
209*8925Sroot 		if (error) {
210*8925Sroot 			unp_detach(unp);
211*8925Sroot 			goto bad;
212*8925Sroot 		}
213*8925Sroot 	}
214*8925Sroot 	return (0);
215*8925Sroot bad:
216*8925Sroot 	return (error);
217*8925Sroot }
218*8925Sroot 
219*8925Sroot unp_disconnect(unp)
220*8925Sroot 	struct unpcb *unp;
221*8925Sroot {
222*8925Sroot 	register struct unpcb *unp2 = unp->unp_conn;
223*8925Sroot 
224*8925Sroot 	if (unp2 == 0)
225*8925Sroot 		return;
226*8925Sroot 	unp->unp_conn = 0;
227*8925Sroot 	soisdisconnected(unp->unp_socket);
228*8925Sroot 	switch (unp->unp_socket->so_type) {
229*8925Sroot 
230*8925Sroot 	case SOCK_DGRAM:
231*8925Sroot 		if (unp2->unp_refs == unp)
232*8925Sroot 			unp2->unp_refs = unp->unp_nextref;
233*8925Sroot 		else {
234*8925Sroot 			unp2 = unp2->unp_refs;
235*8925Sroot 			for (;;) {
236*8925Sroot 				if (unp2 == 0)
237*8925Sroot 					panic("unp_disconnect");
238*8925Sroot 				if (unp2->unp_nextref == unp)
239*8925Sroot 					break;
240*8925Sroot 				unp2 = unp2->unp_nextref;
241*8925Sroot 			}
242*8925Sroot 			unp2->unp_nextref = unp->unp_nextref;
243*8925Sroot 		}
244*8925Sroot 		unp->unp_nextref = 0;
245*8925Sroot 		break;
246*8925Sroot 
247*8925Sroot 	case SOCK_STREAM:
248*8925Sroot 		unp2->unp_conn = 0;
249*8925Sroot 		soisdisconnected(unp2->unp_socket);
250*8925Sroot 		unp_drop(unp2, ECONNRESET);
251*8925Sroot 		break;
252*8925Sroot 	}
253*8925Sroot }
254*8925Sroot 
255*8925Sroot unp_abort(unp)
256*8925Sroot 	struct unpcb *unp;
257*8925Sroot {
258*8925Sroot 
259*8925Sroot 	unp_detach(unp);
260*8925Sroot }
261*8925Sroot 
262*8925Sroot unp_detach(unp)
263*8925Sroot 	struct unpcb *unp;
264*8925Sroot {
265*8925Sroot 
266*8925Sroot 	if (unp->unp_inode) {
267*8925Sroot 		irele(unp->unp_inode);
268*8925Sroot 		unp->unp_inode = 0;
269*8925Sroot 	}
270*8925Sroot 	if (unp->unp_conn)
271*8925Sroot 		unp_disconnect(unp);
272*8925Sroot 	while (unp->unp_refs)
273*8925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
274*8925Sroot 	soisdisconnected(unp->unp_socket);
275*8925Sroot 	unp->unp_socket->so_pcb = 0;
276*8925Sroot 	m_free(dtom(unp));
277*8925Sroot }
278*8925Sroot 
279*8925Sroot unp_usrclosed(unp)
280*8925Sroot 	struct unpcb *unp;
281*8925Sroot {
282*8925Sroot 	register struct socket *so = unp->unp_socket;
283*8925Sroot 
284*8925Sroot #ifdef sometimes /* ??? */
285*8925Sroot 	soisdisconnected(unp->unp_socket);
286*8925Sroot #endif
287*8925Sroot }
288*8925Sroot 
289*8925Sroot unp_drop(unp, errno)
290*8925Sroot 	struct unpcb *unp;
291*8925Sroot 	int errno;
292*8925Sroot {
293*8925Sroot 
294*8925Sroot 	unp->unp_socket->so_error = errno;
295*8925Sroot 	unp_disconnect(unp);
296*8925Sroot }
297*8925Sroot 
298*8925Sroot unp_drain()
299*8925Sroot {
300*8925Sroot 
301*8925Sroot }
302*8925Sroot 
303*8925Sroot unp_bind(unp, soun)
304*8925Sroot 	struct unpcb *unp;
305*8925Sroot 	struct sockaddr_un *soun;
306*8925Sroot {
307*8925Sroot 	register struct inode *ip;
308*8925Sroot 	int error;
309*8925Sroot 	extern schar();
310*8925Sroot 
311*8925Sroot 	u.u_dirp = soun->sun_path;
312*8925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
313*8925Sroot 	ip = namei(schar, 1, 1);
314*8925Sroot 	if (ip) {
315*8925Sroot 		iput(ip);
316*8925Sroot 		return (EEXIST);
317*8925Sroot 	}
318*8925Sroot 	ip = maknode(IFSOCK | 0777);
319*8925Sroot 	if (ip == NULL) {
320*8925Sroot 		error = u.u_error;		/* XXX */
321*8925Sroot 		u.u_error = 0;			/* XXX */
322*8925Sroot 		return (error);
323*8925Sroot 	}
324*8925Sroot 	ip->i_socket = unp->unp_socket;
325*8925Sroot 	unp->unp_inode = ip;
326*8925Sroot 	iunlock(ip);			/* but keep reference */
327*8925Sroot 	return (0);
328*8925Sroot }
329*8925Sroot 
330*8925Sroot unp_connect(so, soun)
331*8925Sroot 	struct socket *so;
332*8925Sroot 	struct sockaddr_un *soun;
333*8925Sroot {
334*8925Sroot 	struct inode *ip;
335*8925Sroot 	int error;
336*8925Sroot 
337*8925Sroot 	u.u_dirp = soun->sun_path;
338*8925Sroot 	soun->sun_path[sizeof(soun->sun_path)-1] = 0;
339*8925Sroot 	ip = namei(schar, 0, 1);
340*8925Sroot 	if (ip == 0) {
341*8925Sroot 		error = u.u_error;
342*8925Sroot 		u.u_error = 0;
343*8925Sroot 		return (ENOENT);
344*8925Sroot 	}
345*8925Sroot 	error = unp_connectip(so, ip);
346*8925Sroot 	return (error);
347*8925Sroot }
348*8925Sroot 
349*8925Sroot unp_connectip(so, ip)
350*8925Sroot 	struct socket *so;
351*8925Sroot 	struct inode *ip;
352*8925Sroot {
353*8925Sroot 	struct unpcb *unp = sotounpcb(so);
354*8925Sroot 	struct socket *so2, *so3;
355*8925Sroot 	int error;
356*8925Sroot 	struct unpcb *unp2;
357*8925Sroot 
358*8925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
359*8925Sroot 		error = ENOTSOCK;
360*8925Sroot 		goto bad;
361*8925Sroot 	}
362*8925Sroot 	so2 = ip->i_socket;
363*8925Sroot 	if (so2 == 0) {
364*8925Sroot 		error = ECONNREFUSED;
365*8925Sroot 		goto bad;
366*8925Sroot 	}
367*8925Sroot 	if (so2->so_type != so->so_type) {
368*8925Sroot 		error = EPROTOTYPE;
369*8925Sroot 		goto bad;
370*8925Sroot 	}
371*8925Sroot 	switch (so->so_type) {
372*8925Sroot 
373*8925Sroot 	case SOCK_DGRAM:
374*8925Sroot 		unp->unp_conn = sotounpcb(so2);
375*8925Sroot 		unp2 = sotounpcb(so2);
376*8925Sroot 		unp->unp_nextref = unp2->unp_refs;
377*8925Sroot 		unp2->unp_refs = unp;
378*8925Sroot 		break;
379*8925Sroot 
380*8925Sroot 	case SOCK_STREAM:
381*8925Sroot 		if ((so2->so_options&SO_ACCEPTCONN) == 0 ||
382*8925Sroot 		    (so3 = sonewconn(so2)) == 0) {
383*8925Sroot 			error = ECONNREFUSED;
384*8925Sroot 			goto bad;
385*8925Sroot 		}
386*8925Sroot 		unp->unp_conn = sotounpcb(so3);
387*8925Sroot 		break;
388*8925Sroot 
389*8925Sroot 	default:
390*8925Sroot 		panic("uipc connip");
391*8925Sroot 	}
392*8925Sroot 	soisconnected(unp->unp_conn->unp_socket);
393*8925Sroot 	soisconnected(so);
394*8925Sroot 	iput(ip);
395*8925Sroot 	return (0);
396*8925Sroot bad:
397*8925Sroot 	iput(ip);
398*8925Sroot 	return (error);
399*8925Sroot }
400