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