Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
ef15363e | 6 | * @(#)uipc_syscalls.c 7.2 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
c8c7dd0e | 8 | |
94368568 | 9 | #include "param.h" |
94368568 JB |
10 | #include "dir.h" |
11 | #include "user.h" | |
94368568 | 12 | #include "file.h" |
94368568 JB |
13 | #include "buf.h" |
14 | #include "mbuf.h" | |
15 | #include "protosw.h" | |
16 | #include "socket.h" | |
17 | #include "socketvar.h" | |
4147b3f6 | 18 | |
c8c7dd0e | 19 | /* |
cf012934 | 20 | * System call interface to the socket abstraction. |
c8c7dd0e BJ |
21 | */ |
22 | ||
88a7a62a SL |
23 | struct file *getsock(); |
24 | extern struct fileops socketops; | |
25 | ||
cf012934 | 26 | socket() |
c8c7dd0e | 27 | { |
cc15ab5d | 28 | register struct a { |
cf012934 | 29 | int domain; |
cc15ab5d | 30 | int type; |
cf012934 | 31 | int protocol; |
cc15ab5d | 32 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 33 | struct socket *so; |
cc15ab5d | 34 | register struct file *fp; |
c8c7dd0e | 35 | |
dfb67abe | 36 | if ((fp = falloc()) == NULL) |
66f52238 | 37 | return; |
4147b3f6 BJ |
38 | fp->f_flag = FREAD|FWRITE; |
39 | fp->f_type = DTYPE_SOCKET; | |
88a7a62a | 40 | fp->f_ops = &socketops; |
66f52238 | 41 | u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol); |
cc15ab5d BJ |
42 | if (u.u_error) |
43 | goto bad; | |
88a7a62a | 44 | fp->f_data = (caddr_t)so; |
cc15ab5d BJ |
45 | return; |
46 | bad: | |
47 | u.u_ofile[u.u_r.r_val1] = 0; | |
48 | fp->f_count = 0; | |
c8c7dd0e | 49 | } |
ae921915 | 50 | |
cf012934 | 51 | bind() |
ae921915 | 52 | { |
2b4b57cd | 53 | register struct a { |
cf012934 BJ |
54 | int s; |
55 | caddr_t name; | |
56 | int namelen; | |
2b4b57cd | 57 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 58 | register struct file *fp; |
cf012934 | 59 | struct mbuf *nam; |
ae921915 | 60 | |
88a7a62a | 61 | fp = getsock(uap->s); |
cf012934 BJ |
62 | if (fp == 0) |
63 | return; | |
98447d3f | 64 | u.u_error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME); |
cf012934 BJ |
65 | if (u.u_error) |
66 | return; | |
88a7a62a | 67 | u.u_error = sobind((struct socket *)fp->f_data, nam); |
cf012934 | 68 | m_freem(nam); |
cf012934 BJ |
69 | } |
70 | ||
71 | listen() | |
72 | { | |
73 | register struct a { | |
74 | int s; | |
75 | int backlog; | |
76 | } *uap = (struct a *)u.u_ap; | |
77 | register struct file *fp; | |
78 | ||
88a7a62a | 79 | fp = getsock(uap->s); |
2b4b57cd BJ |
80 | if (fp == 0) |
81 | return; | |
88a7a62a | 82 | u.u_error = solisten((struct socket *)fp->f_data, uap->backlog); |
cf012934 BJ |
83 | } |
84 | ||
85 | accept() | |
86 | { | |
87 | register struct a { | |
88 | int s; | |
89 | caddr_t name; | |
90 | int *anamelen; | |
cf012934 BJ |
91 | } *uap = (struct a *)u.u_ap; |
92 | register struct file *fp; | |
93 | struct mbuf *nam; | |
cf012934 BJ |
94 | int namelen; |
95 | int s; | |
96 | register struct socket *so; | |
97 | ||
98 | if (uap->name == 0) | |
99 | goto noname; | |
127f7d76 SL |
100 | u.u_error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen, |
101 | sizeof (namelen)); | |
102 | if (u.u_error) | |
cf012934 | 103 | return; |
b32450f4 | 104 | if (useracc((caddr_t)uap->name, (u_int)namelen, B_WRITE) == 0) { |
cf012934 BJ |
105 | u.u_error = EFAULT; |
106 | return; | |
107 | } | |
108 | noname: | |
88a7a62a | 109 | fp = getsock(uap->s); |
cf012934 | 110 | if (fp == 0) |
66f52238 | 111 | return; |
2b4b57cd | 112 | s = splnet(); |
88a7a62a | 113 | so = (struct socket *)fp->f_data; |
4147b3f6 BJ |
114 | if ((so->so_options & SO_ACCEPTCONN) == 0) { |
115 | u.u_error = EINVAL; | |
116 | splx(s); | |
66f52238 | 117 | return; |
4147b3f6 BJ |
118 | } |
119 | if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { | |
2b4b57cd BJ |
120 | u.u_error = EWOULDBLOCK; |
121 | splx(s); | |
66f52238 | 122 | return; |
2b4b57cd | 123 | } |
4147b3f6 | 124 | while (so->so_qlen == 0 && so->so_error == 0) { |
62229532 BJ |
125 | if (so->so_state & SS_CANTRCVMORE) { |
126 | so->so_error = ECONNABORTED; | |
127 | break; | |
128 | } | |
d08c5322 | 129 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
62229532 | 130 | } |
f269ef23 BJ |
131 | if (so->so_error) { |
132 | u.u_error = so->so_error; | |
f4ed5810 | 133 | so->so_error = 0; |
f269ef23 | 134 | splx(s); |
66f52238 | 135 | return; |
f269ef23 | 136 | } |
88a7a62a | 137 | if (ufalloc(0) < 0) { |
4147b3f6 | 138 | splx(s); |
66f52238 | 139 | return; |
4147b3f6 BJ |
140 | } |
141 | fp = falloc(); | |
142 | if (fp == 0) { | |
143 | u.u_ofile[u.u_r.r_val1] = 0; | |
2b4b57cd | 144 | splx(s); |
66f52238 | 145 | return; |
cf012934 BJ |
146 | } |
147 | { struct socket *aso = so->so_q; | |
148 | if (soqremque(aso, 1) == 0) | |
149 | panic("accept"); | |
150 | so = aso; | |
2b4b57cd | 151 | } |
4147b3f6 BJ |
152 | fp->f_type = DTYPE_SOCKET; |
153 | fp->f_flag = FREAD|FWRITE; | |
88a7a62a SL |
154 | fp->f_ops = &socketops; |
155 | fp->f_data = (caddr_t)so; | |
cce93e4b | 156 | nam = m_get(M_WAIT, MT_SONAME); |
66f52238 | 157 | (void) soaccept(so, nam); |
cf012934 BJ |
158 | if (uap->name) { |
159 | if (namelen > nam->m_len) | |
160 | namelen = nam->m_len; | |
161 | /* SHOULD COPY OUT A CHAIN HERE */ | |
b32450f4 BJ |
162 | (void) copyout(mtod(nam, caddr_t), (caddr_t)uap->name, |
163 | (u_int)namelen); | |
164 | (void) copyout((caddr_t)&namelen, (caddr_t)uap->anamelen, | |
cf012934 BJ |
165 | sizeof (*uap->anamelen)); |
166 | } | |
167 | m_freem(nam); | |
2b4b57cd | 168 | splx(s); |
ae921915 BJ |
169 | } |
170 | ||
cf012934 | 171 | connect() |
c8c7dd0e BJ |
172 | { |
173 | register struct a { | |
cf012934 BJ |
174 | int s; |
175 | caddr_t name; | |
176 | int namelen; | |
c8c7dd0e | 177 | } *uap = (struct a *)u.u_ap; |
c8c7dd0e BJ |
178 | register struct file *fp; |
179 | register struct socket *so; | |
cf012934 | 180 | struct mbuf *nam; |
c8c7dd0e BJ |
181 | int s; |
182 | ||
88a7a62a | 183 | fp = getsock(uap->s); |
c8c7dd0e BJ |
184 | if (fp == 0) |
185 | return; | |
88a7a62a | 186 | so = (struct socket *)fp->f_data; |
a7a77c02 MK |
187 | if ((so->so_state & SS_NBIO) && |
188 | (so->so_state & SS_ISCONNECTING)) { | |
6222acc3 | 189 | u.u_error = EALREADY; |
a7a77c02 MK |
190 | return; |
191 | } | |
98447d3f | 192 | u.u_error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME); |
c8c7dd0e BJ |
193 | if (u.u_error) |
194 | return; | |
66f52238 | 195 | u.u_error = soconnect(so, nam); |
cf012934 BJ |
196 | if (u.u_error) |
197 | goto bad; | |
6222acc3 MK |
198 | if ((so->so_state & SS_NBIO) && |
199 | (so->so_state & SS_ISCONNECTING)) { | |
200 | u.u_error = EINPROGRESS; | |
201 | m_freem(nam); | |
202 | return; | |
203 | } | |
c8c7dd0e | 204 | s = splnet(); |
88a7a62a SL |
205 | if (setjmp(&u.u_qsave)) { |
206 | if (u.u_error == 0) | |
207 | u.u_error = EINTR; | |
208 | goto bad2; | |
c8c7dd0e | 209 | } |
cc15ab5d | 210 | while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) |
c8c7dd0e BJ |
211 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
212 | u.u_error = so->so_error; | |
cc15ab5d | 213 | so->so_error = 0; |
88a7a62a | 214 | bad2: |
cc15ab5d | 215 | splx(s); |
cf012934 | 216 | bad: |
6750daae | 217 | so->so_state &= ~SS_ISCONNECTING; |
cf012934 | 218 | m_freem(nam); |
c8c7dd0e BJ |
219 | } |
220 | ||
cf012934 BJ |
221 | socketpair() |
222 | { | |
5a48956d SL |
223 | register struct a { |
224 | int domain; | |
225 | int type; | |
226 | int protocol; | |
227 | int *rsv; | |
228 | } *uap = (struct a *)u.u_ap; | |
229 | register struct file *fp1, *fp2; | |
230 | struct socket *so1, *so2; | |
231 | int sv[2]; | |
cf012934 | 232 | |
5a48956d SL |
233 | if (useracc((caddr_t)uap->rsv, 2 * sizeof (int), B_WRITE) == 0) { |
234 | u.u_error = EFAULT; | |
235 | return; | |
236 | } | |
237 | u.u_error = socreate(uap->domain, &so1, uap->type, uap->protocol); | |
238 | if (u.u_error) | |
239 | return; | |
240 | u.u_error = socreate(uap->domain, &so2, uap->type, uap->protocol); | |
241 | if (u.u_error) | |
242 | goto free; | |
243 | fp1 = falloc(); | |
244 | if (fp1 == NULL) | |
245 | goto free2; | |
246 | sv[0] = u.u_r.r_val1; | |
247 | fp1->f_flag = FREAD|FWRITE; | |
248 | fp1->f_type = DTYPE_SOCKET; | |
249 | fp1->f_ops = &socketops; | |
250 | fp1->f_data = (caddr_t)so1; | |
251 | fp2 = falloc(); | |
252 | if (fp2 == NULL) | |
253 | goto free3; | |
254 | fp2->f_flag = FREAD|FWRITE; | |
255 | fp2->f_type = DTYPE_SOCKET; | |
256 | fp2->f_ops = &socketops; | |
257 | fp2->f_data = (caddr_t)so2; | |
258 | sv[1] = u.u_r.r_val1; | |
259 | u.u_error = soconnect2(so1, so2); | |
260 | if (u.u_error) | |
261 | goto free4; | |
33446404 MK |
262 | if (uap->type == SOCK_DGRAM) { |
263 | /* | |
264 | * Datagram socket connection is asymmetric. | |
265 | */ | |
266 | u.u_error = soconnect2(so2, so1); | |
267 | if (u.u_error) | |
268 | goto free4; | |
269 | } | |
270 | u.u_r.r_val1 = 0; | |
5a48956d SL |
271 | (void) copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int)); |
272 | return; | |
273 | free4: | |
274 | fp2->f_count = 0; | |
275 | u.u_ofile[sv[1]] = 0; | |
276 | free3: | |
277 | fp1->f_count = 0; | |
278 | u.u_ofile[sv[0]] = 0; | |
279 | free2: | |
8011f5df | 280 | (void)soclose(so2); |
5a48956d | 281 | free: |
8011f5df | 282 | (void)soclose(so1); |
cf012934 BJ |
283 | } |
284 | ||
285 | sendto() | |
c8c7dd0e BJ |
286 | { |
287 | register struct a { | |
cf012934 BJ |
288 | int s; |
289 | caddr_t buf; | |
290 | int len; | |
291 | int flags; | |
292 | caddr_t to; | |
293 | int tolen; | |
c8c7dd0e | 294 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 295 | struct msghdr msg; |
d3d550b5 | 296 | struct iovec aiov; |
c8c7dd0e | 297 | |
88a7a62a SL |
298 | msg.msg_name = uap->to; |
299 | msg.msg_namelen = uap->tolen; | |
300 | msg.msg_iov = &aiov; | |
301 | msg.msg_iovlen = 1; | |
cf012934 BJ |
302 | aiov.iov_base = uap->buf; |
303 | aiov.iov_len = uap->len; | |
88a7a62a SL |
304 | msg.msg_accrights = 0; |
305 | msg.msg_accrightslen = 0; | |
306 | sendit(uap->s, &msg, uap->flags); | |
c8c7dd0e BJ |
307 | } |
308 | ||
cf012934 | 309 | send() |
cc15ab5d BJ |
310 | { |
311 | register struct a { | |
cf012934 BJ |
312 | int s; |
313 | caddr_t buf; | |
314 | int len; | |
315 | int flags; | |
cc15ab5d | 316 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 317 | struct msghdr msg; |
a6b6f679 | 318 | struct iovec aiov; |
cc15ab5d | 319 | |
88a7a62a SL |
320 | msg.msg_name = 0; |
321 | msg.msg_namelen = 0; | |
322 | msg.msg_iov = &aiov; | |
323 | msg.msg_iovlen = 1; | |
cf012934 BJ |
324 | aiov.iov_base = uap->buf; |
325 | aiov.iov_len = uap->len; | |
88a7a62a SL |
326 | msg.msg_accrights = 0; |
327 | msg.msg_accrightslen = 0; | |
328 | sendit(uap->s, &msg, uap->flags); | |
329 | } | |
330 | ||
331 | sendmsg() | |
332 | { | |
333 | register struct a { | |
334 | int s; | |
335 | caddr_t msg; | |
336 | int flags; | |
337 | } *uap = (struct a *)u.u_ap; | |
338 | struct msghdr msg; | |
339 | struct iovec aiov[MSG_MAXIOVLEN]; | |
340 | ||
341 | u.u_error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)); | |
342 | if (u.u_error) | |
343 | return; | |
344 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
345 | u.u_error = EMSGSIZE; | |
cf012934 BJ |
346 | return; |
347 | } | |
88a7a62a SL |
348 | u.u_error = |
349 | copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, | |
350 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); | |
cf012934 BJ |
351 | if (u.u_error) |
352 | return; | |
88a7a62a | 353 | msg.msg_iov = aiov; |
88a7a62a SL |
354 | sendit(uap->s, &msg, uap->flags); |
355 | } | |
356 | ||
357 | sendit(s, mp, flags) | |
358 | int s; | |
359 | register struct msghdr *mp; | |
360 | int flags; | |
361 | { | |
362 | register struct file *fp; | |
363 | struct uio auio; | |
364 | register struct iovec *iov; | |
365 | register int i; | |
366 | struct mbuf *to, *rights; | |
367 | int len; | |
368 | ||
369 | fp = getsock(s); | |
370 | if (fp == 0) | |
371 | return; | |
372 | auio.uio_iov = mp->msg_iov; | |
373 | auio.uio_iovcnt = mp->msg_iovlen; | |
c41770c0 | 374 | auio.uio_segflg = UIO_USERSPACE; |
88a7a62a SL |
375 | auio.uio_offset = 0; /* XXX */ |
376 | auio.uio_resid = 0; | |
377 | iov = mp->msg_iov; | |
125c8f95 | 378 | for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
88a7a62a SL |
379 | if (iov->iov_len < 0) { |
380 | u.u_error = EINVAL; | |
381 | return; | |
382 | } | |
0f6422b0 MK |
383 | if (iov->iov_len == 0) |
384 | continue; | |
88a7a62a SL |
385 | if (useracc(iov->iov_base, (u_int)iov->iov_len, B_READ) == 0) { |
386 | u.u_error = EFAULT; | |
387 | return; | |
388 | } | |
389 | auio.uio_resid += iov->iov_len; | |
88a7a62a SL |
390 | } |
391 | if (mp->msg_name) { | |
392 | u.u_error = | |
98447d3f | 393 | sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME); |
88a7a62a SL |
394 | if (u.u_error) |
395 | return; | |
396 | } else | |
397 | to = 0; | |
398 | if (mp->msg_accrights) { | |
399 | u.u_error = | |
98447d3f MK |
400 | sockargs(&rights, mp->msg_accrights, mp->msg_accrightslen, |
401 | MT_RIGHTS); | |
88a7a62a SL |
402 | if (u.u_error) |
403 | goto bad; | |
404 | } else | |
405 | rights = 0; | |
406 | len = auio.uio_resid; | |
407 | u.u_error = | |
408 | sosend((struct socket *)fp->f_data, to, &auio, flags, rights); | |
409 | u.u_r.r_val1 = len - auio.uio_resid; | |
410 | if (rights) | |
411 | m_freem(rights); | |
412 | bad: | |
413 | if (to) | |
414 | m_freem(to); | |
cf012934 BJ |
415 | } |
416 | ||
417 | recvfrom() | |
418 | { | |
419 | register struct a { | |
420 | int s; | |
421 | caddr_t buf; | |
422 | int len; | |
423 | int flags; | |
424 | caddr_t from; | |
425 | int *fromlenaddr; | |
426 | } *uap = (struct a *)u.u_ap; | |
88a7a62a | 427 | struct msghdr msg; |
cf012934 | 428 | struct iovec aiov; |
88a7a62a | 429 | int len; |
cf012934 | 430 | |
88a7a62a SL |
431 | u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&len, |
432 | sizeof (len)); | |
127f7d76 | 433 | if (u.u_error) |
cf012934 | 434 | return; |
88a7a62a SL |
435 | msg.msg_name = uap->from; |
436 | msg.msg_namelen = len; | |
437 | msg.msg_iov = &aiov; | |
438 | msg.msg_iovlen = 1; | |
cf012934 BJ |
439 | aiov.iov_base = uap->buf; |
440 | aiov.iov_len = uap->len; | |
88a7a62a SL |
441 | msg.msg_accrights = 0; |
442 | msg.msg_accrightslen = 0; | |
443 | recvit(uap->s, &msg, uap->flags, (caddr_t)uap->fromlenaddr, (caddr_t)0); | |
cf012934 BJ |
444 | } |
445 | ||
446 | recv() | |
447 | { | |
448 | register struct a { | |
449 | int s; | |
450 | caddr_t buf; | |
451 | int len; | |
452 | int flags; | |
453 | } *uap = (struct a *)u.u_ap; | |
88a7a62a | 454 | struct msghdr msg; |
cf012934 BJ |
455 | struct iovec aiov; |
456 | ||
88a7a62a SL |
457 | msg.msg_name = 0; |
458 | msg.msg_namelen = 0; | |
459 | msg.msg_iov = &aiov; | |
460 | msg.msg_iovlen = 1; | |
cf012934 BJ |
461 | aiov.iov_base = uap->buf; |
462 | aiov.iov_len = uap->len; | |
88a7a62a SL |
463 | msg.msg_accrights = 0; |
464 | msg.msg_accrightslen = 0; | |
465 | recvit(uap->s, &msg, uap->flags, (caddr_t)0, (caddr_t)0); | |
cf012934 BJ |
466 | } |
467 | ||
88a7a62a | 468 | recvmsg() |
cf012934 | 469 | { |
88a7a62a SL |
470 | register struct a { |
471 | int s; | |
472 | struct msghdr *msg; | |
473 | int flags; | |
474 | } *uap = (struct a *)u.u_ap; | |
475 | struct msghdr msg; | |
476 | struct iovec aiov[MSG_MAXIOVLEN]; | |
cf012934 | 477 | |
88a7a62a SL |
478 | u.u_error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)); |
479 | if (u.u_error) | |
480 | return; | |
481 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
482 | u.u_error = EMSGSIZE; | |
483 | return; | |
484 | } | |
485 | u.u_error = | |
486 | copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, | |
487 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); | |
488 | if (u.u_error) | |
489 | return; | |
490 | msg.msg_iov = aiov; | |
491 | if (msg.msg_accrights) | |
492 | if (useracc((caddr_t)msg.msg_accrights, | |
493 | (unsigned)msg.msg_accrightslen, B_WRITE) == 0) { | |
494 | u.u_error = EFAULT; | |
495 | return; | |
496 | } | |
497 | recvit(uap->s, &msg, uap->flags, | |
498 | (caddr_t)&uap->msg->msg_namelen, | |
499 | (caddr_t)&uap->msg->msg_accrightslen); | |
cf012934 BJ |
500 | } |
501 | ||
88a7a62a SL |
502 | recvit(s, mp, flags, namelenp, rightslenp) |
503 | int s; | |
504 | register struct msghdr *mp; | |
505 | int flags; | |
506 | caddr_t namelenp, rightslenp; | |
cf012934 | 507 | { |
88a7a62a SL |
508 | register struct file *fp; |
509 | struct uio auio; | |
510 | register struct iovec *iov; | |
511 | register int i; | |
512 | struct mbuf *from, *rights; | |
513 | int len; | |
514 | ||
515 | fp = getsock(s); | |
516 | if (fp == 0) | |
517 | return; | |
518 | auio.uio_iov = mp->msg_iov; | |
519 | auio.uio_iovcnt = mp->msg_iovlen; | |
c41770c0 | 520 | auio.uio_segflg = UIO_USERSPACE; |
88a7a62a SL |
521 | auio.uio_offset = 0; /* XXX */ |
522 | auio.uio_resid = 0; | |
523 | iov = mp->msg_iov; | |
125c8f95 | 524 | for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
88a7a62a SL |
525 | if (iov->iov_len < 0) { |
526 | u.u_error = EINVAL; | |
527 | return; | |
528 | } | |
0f6422b0 MK |
529 | if (iov->iov_len == 0) |
530 | continue; | |
88a7a62a SL |
531 | if (useracc(iov->iov_base, (u_int)iov->iov_len, B_WRITE) == 0) { |
532 | u.u_error = EFAULT; | |
533 | return; | |
534 | } | |
535 | auio.uio_resid += iov->iov_len; | |
88a7a62a SL |
536 | } |
537 | len = auio.uio_resid; | |
538 | u.u_error = | |
539 | soreceive((struct socket *)fp->f_data, &from, &auio, | |
540 | flags, &rights); | |
541 | u.u_r.r_val1 = len - auio.uio_resid; | |
542 | if (mp->msg_name) { | |
543 | len = mp->msg_namelen; | |
544 | if (len <= 0 || from == 0) | |
545 | len = 0; | |
546 | else { | |
547 | if (len > from->m_len) | |
548 | len = from->m_len; | |
549 | (void) copyout((caddr_t)mtod(from, caddr_t), | |
550 | (caddr_t)mp->msg_name, (unsigned)len); | |
551 | } | |
552 | (void) copyout((caddr_t)&len, namelenp, sizeof (int)); | |
553 | } | |
554 | if (mp->msg_accrights) { | |
555 | len = mp->msg_accrightslen; | |
556 | if (len <= 0 || rights == 0) | |
557 | len = 0; | |
558 | else { | |
559 | if (len > rights->m_len) | |
560 | len = rights->m_len; | |
561 | (void) copyout((caddr_t)mtod(rights, caddr_t), | |
562 | (caddr_t)mp->msg_accrights, (unsigned)len); | |
563 | } | |
564 | (void) copyout((caddr_t)&len, rightslenp, sizeof (int)); | |
565 | } | |
566 | if (rights) | |
567 | m_freem(rights); | |
568 | if (from) | |
569 | m_freem(from); | |
cf012934 BJ |
570 | } |
571 | ||
572 | shutdown() | |
573 | { | |
6ef233bf SL |
574 | struct a { |
575 | int s; | |
576 | int how; | |
577 | } *uap = (struct a *)u.u_ap; | |
578 | struct file *fp; | |
cf012934 | 579 | |
88a7a62a | 580 | fp = getsock(uap->s); |
6ef233bf SL |
581 | if (fp == 0) |
582 | return; | |
88a7a62a | 583 | u.u_error = soshutdown((struct socket *)fp->f_data, uap->how); |
cf012934 BJ |
584 | } |
585 | ||
66f52238 SL |
586 | setsockopt() |
587 | { | |
588 | struct a { | |
589 | int s; | |
590 | int level; | |
591 | int name; | |
592 | caddr_t val; | |
593 | int valsize; | |
594 | } *uap = (struct a *)u.u_ap; | |
595 | struct file *fp; | |
d2cba8de | 596 | struct mbuf *m = NULL; |
66f52238 | 597 | |
88a7a62a | 598 | fp = getsock(uap->s); |
66f52238 SL |
599 | if (fp == 0) |
600 | return; | |
66f52238 SL |
601 | if (uap->valsize > MLEN) { |
602 | u.u_error = EINVAL; | |
603 | return; | |
604 | } | |
d2cba8de SL |
605 | if (uap->val) { |
606 | m = m_get(M_WAIT, MT_SOOPTS); | |
7c52d753 | 607 | if (m == NULL) { |
d2cba8de SL |
608 | u.u_error = ENOBUFS; |
609 | return; | |
610 | } | |
88a7a62a SL |
611 | u.u_error = |
612 | copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize); | |
61ec2127 SL |
613 | if (u.u_error) { |
614 | (void) m_free(m); | |
615 | return; | |
616 | } | |
d2cba8de | 617 | m->m_len = uap->valsize; |
66f52238 | 618 | } |
88a7a62a SL |
619 | u.u_error = |
620 | sosetopt((struct socket *)fp->f_data, uap->level, uap->name, m); | |
66f52238 SL |
621 | } |
622 | ||
623 | getsockopt() | |
624 | { | |
625 | struct a { | |
626 | int s; | |
627 | int level; | |
628 | int name; | |
629 | caddr_t val; | |
630 | int *avalsize; | |
631 | } *uap = (struct a *)u.u_ap; | |
632 | struct file *fp; | |
d2cba8de | 633 | struct mbuf *m = NULL; |
66f52238 SL |
634 | int valsize; |
635 | ||
88a7a62a | 636 | fp = getsock(uap->s); |
66f52238 SL |
637 | if (fp == 0) |
638 | return; | |
d2cba8de SL |
639 | if (uap->val) { |
640 | u.u_error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize, | |
641 | sizeof (valsize)); | |
642 | if (u.u_error) | |
643 | return; | |
61ec2127 SL |
644 | } else |
645 | valsize = 0; | |
88a7a62a | 646 | u.u_error = |
61ec2127 | 647 | sogetopt((struct socket *)fp->f_data, uap->level, uap->name, &m); |
66f52238 SL |
648 | if (u.u_error) |
649 | goto bad; | |
61ec2127 | 650 | if (uap->val && valsize && m != NULL) { |
d2cba8de SL |
651 | if (valsize > m->m_len) |
652 | valsize = m->m_len; | |
653 | u.u_error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize); | |
654 | if (u.u_error) | |
655 | goto bad; | |
656 | u.u_error = copyout((caddr_t)&valsize, (caddr_t)uap->avalsize, | |
657 | sizeof (valsize)); | |
658 | } | |
66f52238 | 659 | bad: |
d2cba8de SL |
660 | if (m != NULL) |
661 | (void) m_free(m); | |
66f52238 SL |
662 | } |
663 | ||
cf012934 BJ |
664 | pipe() |
665 | { | |
666 | register struct file *rf, *wf; | |
667 | struct socket *rso, *wso; | |
668 | int r; | |
669 | ||
88a7a62a | 670 | u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0); |
2b4b57cd BJ |
671 | if (u.u_error) |
672 | return; | |
88a7a62a | 673 | u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0); |
cf012934 BJ |
674 | if (u.u_error) |
675 | goto free; | |
676 | rf = falloc(); | |
677 | if (rf == NULL) | |
678 | goto free2; | |
679 | r = u.u_r.r_val1; | |
680 | rf->f_flag = FREAD; | |
681 | rf->f_type = DTYPE_SOCKET; | |
88a7a62a SL |
682 | rf->f_ops = &socketops; |
683 | rf->f_data = (caddr_t)rso; | |
cf012934 BJ |
684 | wf = falloc(); |
685 | if (wf == NULL) | |
686 | goto free3; | |
687 | wf->f_flag = FWRITE; | |
688 | wf->f_type = DTYPE_SOCKET; | |
88a7a62a SL |
689 | wf->f_ops = &socketops; |
690 | wf->f_data = (caddr_t)wso; | |
cf012934 BJ |
691 | u.u_r.r_val2 = u.u_r.r_val1; |
692 | u.u_r.r_val1 = r; | |
d97afdcc | 693 | if (u.u_error = unp_connect2(wso, rso)) |
cf012934 | 694 | goto free4; |
9c58d471 MK |
695 | wso->so_state |= SS_CANTRCVMORE; |
696 | rso->so_state |= SS_CANTSENDMORE; | |
cf012934 BJ |
697 | return; |
698 | free4: | |
699 | wf->f_count = 0; | |
700 | u.u_ofile[u.u_r.r_val2] = 0; | |
701 | free3: | |
702 | rf->f_count = 0; | |
703 | u.u_ofile[r] = 0; | |
704 | free2: | |
8011f5df | 705 | (void)soclose(wso); |
cf012934 | 706 | free: |
8011f5df | 707 | (void)soclose(rso); |
cc15ab5d | 708 | } |
a3076b07 BJ |
709 | |
710 | /* | |
70f2eac5 | 711 | * Get socket name. |
a3076b07 | 712 | */ |
70f2eac5 | 713 | getsockname() |
a3076b07 BJ |
714 | { |
715 | register struct a { | |
716 | int fdes; | |
70f2eac5 SL |
717 | caddr_t asa; |
718 | int *alen; | |
a3076b07 BJ |
719 | } *uap = (struct a *)u.u_ap; |
720 | register struct file *fp; | |
05d69517 | 721 | register struct socket *so; |
cf012934 | 722 | struct mbuf *m; |
70f2eac5 | 723 | int len; |
a3076b07 | 724 | |
88a7a62a | 725 | fp = getsock(uap->fdes); |
a3076b07 BJ |
726 | if (fp == 0) |
727 | return; | |
70f2eac5 SL |
728 | u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); |
729 | if (u.u_error) | |
730 | return; | |
88a7a62a | 731 | so = (struct socket *)fp->f_data; |
cce93e4b | 732 | m = m_getclr(M_WAIT, MT_SONAME); |
7c52d753 SL |
733 | if (m == NULL) { |
734 | u.u_error = ENOBUFS; | |
735 | return; | |
736 | } | |
70f2eac5 SL |
737 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0); |
738 | if (u.u_error) | |
739 | goto bad; | |
740 | if (len > m->m_len) | |
741 | len = m->m_len; | |
742 | u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); | |
05d69517 | 743 | if (u.u_error) |
cf012934 | 744 | goto bad; |
70f2eac5 | 745 | u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); |
cf012934 BJ |
746 | bad: |
747 | m_freem(m); | |
748 | } | |
749 | ||
a7343092 SL |
750 | /* |
751 | * Get name of peer for connected socket. | |
752 | */ | |
753 | getpeername() | |
754 | { | |
755 | register struct a { | |
756 | int fdes; | |
757 | caddr_t asa; | |
758 | int *alen; | |
759 | } *uap = (struct a *)u.u_ap; | |
760 | register struct file *fp; | |
761 | register struct socket *so; | |
762 | struct mbuf *m; | |
763 | int len; | |
764 | ||
765 | fp = getsock(uap->fdes); | |
766 | if (fp == 0) | |
767 | return; | |
768 | so = (struct socket *)fp->f_data; | |
769 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
770 | u.u_error = ENOTCONN; | |
771 | return; | |
772 | } | |
773 | m = m_getclr(M_WAIT, MT_SONAME); | |
774 | if (m == NULL) { | |
775 | u.u_error = ENOBUFS; | |
776 | return; | |
777 | } | |
778 | u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); | |
779 | if (u.u_error) | |
780 | return; | |
781 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0); | |
782 | if (u.u_error) | |
783 | goto bad; | |
784 | if (len > m->m_len) | |
785 | len = m->m_len; | |
786 | u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); | |
787 | if (u.u_error) | |
788 | goto bad; | |
789 | u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); | |
790 | bad: | |
791 | m_freem(m); | |
792 | } | |
793 | ||
98447d3f | 794 | sockargs(aname, name, namelen, type) |
cf012934 BJ |
795 | struct mbuf **aname; |
796 | caddr_t name; | |
98447d3f | 797 | int namelen, type; |
cf012934 BJ |
798 | { |
799 | register struct mbuf *m; | |
127f7d76 | 800 | int error; |
cf012934 BJ |
801 | |
802 | if (namelen > MLEN) | |
803 | return (EINVAL); | |
98447d3f | 804 | m = m_get(M_WAIT, type); |
7c52d753 SL |
805 | if (m == NULL) |
806 | return (ENOBUFS); | |
cf012934 | 807 | m->m_len = namelen; |
127f7d76 SL |
808 | error = copyin(name, mtod(m, caddr_t), (u_int)namelen); |
809 | if (error) | |
cf012934 | 810 | (void) m_free(m); |
127f7d76 SL |
811 | else |
812 | *aname = m; | |
813 | return (error); | |
cf012934 | 814 | } |
88a7a62a SL |
815 | |
816 | struct file * | |
817 | getsock(fdes) | |
818 | int fdes; | |
819 | { | |
820 | register struct file *fp; | |
821 | ||
822 | fp = getf(fdes); | |
823 | if (fp == NULL) | |
824 | return (0); | |
825 | if (fp->f_type != DTYPE_SOCKET) { | |
826 | u.u_error = ENOTSOCK; | |
827 | return (0); | |
828 | } | |
829 | return (fp); | |
830 | } |