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