Commit | Line | Data |
---|---|---|
f3bb1ae7 | 1 | /* uipc_usrreq.c 1.9 83/04/03 */ |
d6213d15 BJ |
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" | |
4f083fd7 | 13 | #include "../h/nami.h" |
d6213d15 BJ |
14 | |
15 | /* | |
16 | * Unix communications domain. | |
17 | */ | |
18 | ||
19 | /*ARGSUSED*/ | |
c20f7455 | 20 | uipc_usrreq(so, req, m, nam) |
d6213d15 BJ |
21 | struct socket *so; |
22 | int req; | |
fca5570f | 23 | struct mbuf *m, *nam; |
d6213d15 BJ |
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) { | |
4f083fd7 | 35 | error = EISCONN; |
d6213d15 BJ |
36 | break; |
37 | } | |
fca5570f | 38 | error = unp_attach(so); |
d6213d15 BJ |
39 | break; |
40 | ||
41 | case PRU_DETACH: | |
42 | unp_detach(unp); | |
43 | break; | |
44 | ||
4f083fd7 SL |
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 | ||
d6213d15 | 54 | case PRU_CONNECT: |
fca5570f | 55 | error = unp_connect(so, nam); |
d6213d15 BJ |
56 | break; |
57 | ||
58 | case PRU_DISCONNECT: | |
59 | unp_disconnect(unp); | |
60 | break; | |
61 | ||
4f083fd7 SL |
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); | |
d6213d15 BJ |
66 | break; |
67 | ||
68 | case PRU_SHUTDOWN: | |
69 | socantsendmore(so); | |
70 | unp_usrclosed(unp); | |
71 | break; | |
d6213d15 BJ |
72 | |
73 | case PRU_RCVD: | |
74 | switch (so->so_type) { | |
75 | ||
76 | case SOCK_DGRAM: | |
77 | panic("uipc 1"); | |
5fe6f9d1 | 78 | /*NOTREACHED*/ |
d6213d15 | 79 | |
5fe6f9d1 | 80 | case SOCK_STREAM: |
d6213d15 BJ |
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 | |
d6213d15 BJ |
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: | |
fca5570f | 108 | if (nam) { |
d6213d15 BJ |
109 | if (unp->unp_conn) { |
110 | error = EISCONN; | |
111 | break; | |
112 | } | |
fca5570f | 113 | error = unp_connect(so, nam); |
d6213d15 BJ |
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; | |
4f083fd7 SL |
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 */ | |
fca5570f | 128 | if (nam) |
4f083fd7 | 129 | unp_disconnect(unp); |
d6213d15 BJ |
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 | } | |
e14b8185 | 187 | return (error); |
d6213d15 BJ |
188 | } |
189 | ||
190 | int unp_sendspace = 1024*2; | |
191 | int unp_recvspace = 1024*2; | |
192 | ||
4f083fd7 | 193 | unp_attach(so) |
d6213d15 | 194 | struct socket *so; |
d6213d15 | 195 | { |
4f083fd7 | 196 | register struct mbuf *m; |
d6213d15 | 197 | register struct unpcb *unp; |
d6213d15 BJ |
198 | int error; |
199 | ||
200 | error = soreserve(so, unp_sendspace, unp_recvspace); | |
201 | if (error) | |
5fe6f9d1 | 202 | return (error); |
cce93e4b | 203 | m = m_getclr(M_DONTWAIT, MT_PCB); |
5fe6f9d1 SL |
204 | if (m == NULL) |
205 | return (ENOBUFS); | |
d6213d15 BJ |
206 | unp = mtod(m, struct unpcb *); |
207 | so->so_pcb = (caddr_t)unp; | |
208 | unp->unp_socket = so; | |
d6213d15 | 209 | return (0); |
d6213d15 BJ |
210 | } |
211 | ||
d6213d15 | 212 | unp_detach(unp) |
4f083fd7 | 213 | register struct unpcb *unp; |
d6213d15 BJ |
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; | |
4f083fd7 SL |
226 | m_freem(unp->unp_remaddr); |
227 | (void) m_free(dtom(unp)); | |
d6213d15 BJ |
228 | } |
229 | ||
4f083fd7 | 230 | unp_bind(unp, nam) |
d6213d15 | 231 | struct unpcb *unp; |
4f083fd7 | 232 | struct mbuf *nam; |
d6213d15 | 233 | { |
4f083fd7 | 234 | struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
d6213d15 | 235 | register struct inode *ip; |
d6213d15 | 236 | extern schar(); |
4f083fd7 | 237 | int error; |
d6213d15 BJ |
238 | |
239 | u.u_dirp = soun->sun_path; | |
240 | soun->sun_path[sizeof(soun->sun_path)-1] = 0; | |
4f083fd7 | 241 | ip = namei(schar, CREATE, 1); |
d6213d15 BJ |
242 | if (ip) { |
243 | iput(ip); | |
5fe6f9d1 | 244 | return (EADDRINUSE); |
d6213d15 | 245 | } |
f3bb1ae7 SL |
246 | if (error = u.u_error) { |
247 | u.u_error = 0; /* XXX */ | |
248 | return (error); | |
249 | } | |
d6213d15 BJ |
250 | ip = maknode(IFSOCK | 0777); |
251 | if (ip == NULL) { | |
252 | error = u.u_error; /* XXX */ | |
253 | u.u_error = 0; /* XXX */ | |
254 | return (error); | |
255 | } | |
256 | ip->i_socket = unp->unp_socket; | |
257 | unp->unp_inode = ip; | |
258 | iunlock(ip); /* but keep reference */ | |
259 | return (0); | |
260 | } | |
261 | ||
4f083fd7 | 262 | unp_connect(so, nam) |
d6213d15 | 263 | struct socket *so; |
4f083fd7 | 264 | struct mbuf *nam; |
d6213d15 | 265 | { |
4f083fd7 SL |
266 | register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
267 | struct unpcb *unp = sotounpcb(so); | |
268 | register struct inode *ip; | |
d6213d15 | 269 | int error; |
4f083fd7 SL |
270 | struct socket *so2; |
271 | struct unpcb *unp2; | |
d6213d15 BJ |
272 | |
273 | u.u_dirp = soun->sun_path; | |
274 | soun->sun_path[sizeof(soun->sun_path)-1] = 0; | |
4f083fd7 | 275 | ip = namei(schar, LOOKUP, 1); |
d6213d15 BJ |
276 | if (ip == 0) { |
277 | error = u.u_error; | |
278 | u.u_error = 0; | |
5fe6f9d1 | 279 | return (error); /* XXX */ |
d6213d15 | 280 | } |
d6213d15 BJ |
281 | if ((ip->i_mode&IFMT) != IFSOCK) { |
282 | error = ENOTSOCK; | |
283 | goto bad; | |
284 | } | |
285 | so2 = ip->i_socket; | |
286 | if (so2 == 0) { | |
287 | error = ECONNREFUSED; | |
288 | goto bad; | |
289 | } | |
290 | if (so2->so_type != so->so_type) { | |
291 | error = EPROTOTYPE; | |
292 | goto bad; | |
293 | } | |
294 | switch (so->so_type) { | |
295 | ||
296 | case SOCK_DGRAM: | |
297 | unp->unp_conn = sotounpcb(so2); | |
298 | unp2 = sotounpcb(so2); | |
299 | unp->unp_nextref = unp2->unp_refs; | |
300 | unp2->unp_refs = unp; | |
301 | break; | |
302 | ||
303 | case SOCK_STREAM: | |
304 | if ((so2->so_options&SO_ACCEPTCONN) == 0 || | |
4f083fd7 | 305 | (so2 = sonewconn(so2)) == 0) { |
d6213d15 BJ |
306 | error = ECONNREFUSED; |
307 | goto bad; | |
308 | } | |
4f083fd7 SL |
309 | unp2 = sotounpcb(so2); |
310 | unp->unp_conn = unp2; | |
311 | unp2->unp_conn = unp; | |
312 | unp2->unp_remaddr = m_copy(nam, 0, (int)M_COPYALL); | |
d6213d15 BJ |
313 | break; |
314 | ||
315 | default: | |
316 | panic("uipc connip"); | |
317 | } | |
4f083fd7 | 318 | soisconnected(so2); |
d6213d15 BJ |
319 | soisconnected(so); |
320 | iput(ip); | |
321 | return (0); | |
322 | bad: | |
323 | iput(ip); | |
324 | return (error); | |
325 | } | |
4f083fd7 SL |
326 | |
327 | unp_disconnect(unp) | |
328 | struct unpcb *unp; | |
329 | { | |
330 | register struct unpcb *unp2 = unp->unp_conn; | |
331 | ||
332 | if (unp2 == 0) | |
333 | return; | |
334 | unp->unp_conn = 0; | |
335 | soisdisconnected(unp->unp_socket); | |
336 | switch (unp->unp_socket->so_type) { | |
337 | ||
338 | case SOCK_DGRAM: | |
339 | if (unp2->unp_refs == unp) | |
340 | unp2->unp_refs = unp->unp_nextref; | |
341 | else { | |
342 | unp2 = unp2->unp_refs; | |
343 | for (;;) { | |
344 | if (unp2 == 0) | |
345 | panic("unp_disconnect"); | |
346 | if (unp2->unp_nextref == unp) | |
347 | break; | |
348 | unp2 = unp2->unp_nextref; | |
349 | } | |
350 | unp2->unp_nextref = unp->unp_nextref; | |
351 | } | |
352 | unp->unp_nextref = 0; | |
353 | break; | |
354 | ||
355 | case SOCK_STREAM: | |
356 | unp2->unp_conn = 0; | |
357 | soisdisconnected(unp2->unp_socket); | |
4f083fd7 SL |
358 | break; |
359 | } | |
360 | } | |
361 | ||
362 | unp_abort(unp) | |
363 | struct unpcb *unp; | |
364 | { | |
365 | ||
366 | unp_detach(unp); | |
367 | } | |
368 | ||
369 | /*ARGSUSED*/ | |
370 | unp_usrclosed(unp) | |
371 | struct unpcb *unp; | |
372 | { | |
373 | ||
374 | } | |
375 | ||
376 | unp_drop(unp, errno) | |
377 | struct unpcb *unp; | |
378 | int errno; | |
379 | { | |
380 | ||
381 | unp->unp_socket->so_error = errno; | |
382 | unp_disconnect(unp); | |
383 | } | |
384 | ||
385 | unp_drain() | |
386 | { | |
387 | ||
388 | } |