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