Commit | Line | Data |
---|---|---|
cce93e4b | 1 | /* uipc_usrreq.c 1.5 82/12/14 */ |
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*/ | |
fca5570f | 20 | uipc_usrreq(so, req, m, nam, opt) |
d6213d15 BJ |
21 | struct socket *so; |
22 | int req; | |
fca5570f BJ |
23 | struct mbuf *m, *nam; |
24 | struct socketopt *opt; | |
d6213d15 BJ |
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) { | |
4f083fd7 | 36 | error = EISCONN; |
d6213d15 BJ |
37 | break; |
38 | } | |
fca5570f | 39 | error = unp_attach(so); |
d6213d15 BJ |
40 | break; |
41 | ||
42 | case PRU_DETACH: | |
43 | unp_detach(unp); | |
44 | break; | |
45 | ||
4f083fd7 SL |
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 | ||
d6213d15 | 55 | case PRU_CONNECT: |
fca5570f | 56 | error = unp_connect(so, nam); |
d6213d15 BJ |
57 | break; |
58 | ||
59 | case PRU_DISCONNECT: | |
60 | unp_disconnect(unp); | |
61 | break; | |
62 | ||
4f083fd7 SL |
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); | |
d6213d15 BJ |
67 | break; |
68 | ||
69 | case PRU_SHUTDOWN: | |
70 | socantsendmore(so); | |
71 | unp_usrclosed(unp); | |
72 | break; | |
d6213d15 BJ |
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: | |
fca5570f | 109 | if (nam) { |
d6213d15 BJ |
110 | if (unp->unp_conn) { |
111 | error = EISCONN; | |
112 | break; | |
113 | } | |
fca5570f | 114 | error = unp_connect(so, nam); |
d6213d15 BJ |
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; | |
4f083fd7 SL |
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 */ | |
fca5570f | 129 | if (nam) |
4f083fd7 | 130 | unp_disconnect(unp); |
d6213d15 BJ |
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 | ||
4f083fd7 | 194 | unp_attach(so) |
d6213d15 | 195 | struct socket *so; |
d6213d15 | 196 | { |
4f083fd7 | 197 | register struct mbuf *m; |
d6213d15 | 198 | register struct unpcb *unp; |
d6213d15 BJ |
199 | int error; |
200 | ||
201 | error = soreserve(so, unp_sendspace, unp_recvspace); | |
202 | if (error) | |
203 | goto bad; | |
cce93e4b | 204 | m = m_getclr(M_DONTWAIT, MT_PCB); |
d6213d15 BJ |
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; | |
d6213d15 BJ |
212 | return (0); |
213 | bad: | |
214 | return (error); | |
215 | } | |
216 | ||
d6213d15 | 217 | unp_detach(unp) |
4f083fd7 | 218 | register struct unpcb *unp; |
d6213d15 BJ |
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; | |
4f083fd7 SL |
231 | m_freem(unp->unp_remaddr); |
232 | (void) m_free(dtom(unp)); | |
d6213d15 BJ |
233 | } |
234 | ||
4f083fd7 | 235 | unp_bind(unp, nam) |
d6213d15 | 236 | struct unpcb *unp; |
4f083fd7 | 237 | struct mbuf *nam; |
d6213d15 | 238 | { |
4f083fd7 | 239 | struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
d6213d15 | 240 | register struct inode *ip; |
d6213d15 | 241 | extern schar(); |
4f083fd7 | 242 | int error; |
d6213d15 BJ |
243 | |
244 | u.u_dirp = soun->sun_path; | |
245 | soun->sun_path[sizeof(soun->sun_path)-1] = 0; | |
4f083fd7 | 246 | ip = namei(schar, CREATE, 1); |
d6213d15 BJ |
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 | ||
4f083fd7 | 263 | unp_connect(so, nam) |
d6213d15 | 264 | struct socket *so; |
4f083fd7 | 265 | struct mbuf *nam; |
d6213d15 | 266 | { |
4f083fd7 SL |
267 | register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); |
268 | struct unpcb *unp = sotounpcb(so); | |
269 | register struct inode *ip; | |
d6213d15 | 270 | int error; |
4f083fd7 SL |
271 | struct socket *so2; |
272 | struct unpcb *unp2; | |
d6213d15 BJ |
273 | |
274 | u.u_dirp = soun->sun_path; | |
275 | soun->sun_path[sizeof(soun->sun_path)-1] = 0; | |
4f083fd7 | 276 | ip = namei(schar, LOOKUP, 1); |
d6213d15 BJ |
277 | if (ip == 0) { |
278 | error = u.u_error; | |
279 | u.u_error = 0; | |
280 | return (ENOENT); | |
281 | } | |
d6213d15 BJ |
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 || | |
4f083fd7 | 306 | (so2 = sonewconn(so2)) == 0) { |
d6213d15 BJ |
307 | error = ECONNREFUSED; |
308 | goto bad; | |
309 | } | |
4f083fd7 SL |
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); | |
d6213d15 BJ |
314 | break; |
315 | ||
316 | default: | |
317 | panic("uipc connip"); | |
318 | } | |
4f083fd7 | 319 | soisconnected(so2); |
d6213d15 BJ |
320 | soisconnected(so); |
321 | iput(ip); | |
322 | return (0); | |
323 | bad: | |
324 | iput(ip); | |
325 | return (error); | |
326 | } | |
4f083fd7 SL |
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); | |
4f083fd7 SL |
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 | } |