Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
da7c5cc6 | 2 | * |
96e6449f | 3 | * Redistribution and use in source and binary forms are permitted |
616d42db KB |
4 | * provided that the above copyright notice and this paragraph are |
5 | * duplicated in all such forms and that any documentation, | |
6 | * advertising materials, and other materials related to such | |
7 | * distribution and use acknowledge that the software was developed | |
8 | * by the University of California, Berkeley. The name of the | |
9 | * University may not be used to endorse or promote products derived | |
10 | * from this software without specific prior written permission. | |
11 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
12 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
13 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
96e6449f | 14 | * |
c4ec2128 | 15 | * @(#)uipc_syscalls.c 7.10 (Berkeley) %G% |
da7c5cc6 | 16 | */ |
c8c7dd0e | 17 | |
94368568 | 18 | #include "param.h" |
94368568 | 19 | #include "user.h" |
6d47a3da | 20 | #include "proc.h" |
94368568 | 21 | #include "file.h" |
94368568 | 22 | #include "buf.h" |
6d47a3da | 23 | #include "malloc.h" |
94368568 JB |
24 | #include "mbuf.h" |
25 | #include "protosw.h" | |
26 | #include "socket.h" | |
27 | #include "socketvar.h" | |
4147b3f6 | 28 | |
c8c7dd0e | 29 | /* |
cf012934 | 30 | * System call interface to the socket abstraction. |
c8c7dd0e BJ |
31 | */ |
32 | ||
88a7a62a SL |
33 | struct file *getsock(); |
34 | extern struct fileops socketops; | |
35 | ||
cf012934 | 36 | socket() |
c8c7dd0e | 37 | { |
cc15ab5d | 38 | register struct a { |
cf012934 | 39 | int domain; |
cc15ab5d | 40 | int type; |
cf012934 | 41 | int protocol; |
cc15ab5d | 42 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 43 | struct socket *so; |
0c9a45f0 KM |
44 | struct file *fp; |
45 | int fd; | |
c8c7dd0e | 46 | |
0c9a45f0 | 47 | if (u.u_error = falloc(&fp, &fd)) |
66f52238 | 48 | return; |
4147b3f6 BJ |
49 | fp->f_flag = FREAD|FWRITE; |
50 | fp->f_type = DTYPE_SOCKET; | |
88a7a62a | 51 | fp->f_ops = &socketops; |
66f52238 | 52 | u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol); |
cc15ab5d BJ |
53 | if (u.u_error) |
54 | goto bad; | |
88a7a62a | 55 | fp->f_data = (caddr_t)so; |
0c9a45f0 | 56 | u.u_r.r_val1 = fd; |
cc15ab5d BJ |
57 | return; |
58 | bad: | |
0c9a45f0 KM |
59 | u.u_ofile[fd] = 0; |
60 | crfree(fp->f_cred); | |
cc15ab5d | 61 | fp->f_count = 0; |
c8c7dd0e | 62 | } |
ae921915 | 63 | |
cf012934 | 64 | bind() |
ae921915 | 65 | { |
2b4b57cd | 66 | register struct a { |
cf012934 BJ |
67 | int s; |
68 | caddr_t name; | |
69 | int namelen; | |
2b4b57cd | 70 | } *uap = (struct a *)u.u_ap; |
2b4b57cd | 71 | register struct file *fp; |
cf012934 | 72 | struct mbuf *nam; |
ae921915 | 73 | |
88a7a62a | 74 | fp = getsock(uap->s); |
cf012934 BJ |
75 | if (fp == 0) |
76 | return; | |
98447d3f | 77 | u.u_error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME); |
cf012934 BJ |
78 | if (u.u_error) |
79 | return; | |
88a7a62a | 80 | u.u_error = sobind((struct socket *)fp->f_data, nam); |
cf012934 | 81 | m_freem(nam); |
cf012934 BJ |
82 | } |
83 | ||
84 | listen() | |
85 | { | |
86 | register struct a { | |
87 | int s; | |
88 | int backlog; | |
89 | } *uap = (struct a *)u.u_ap; | |
90 | register struct file *fp; | |
91 | ||
88a7a62a | 92 | fp = getsock(uap->s); |
2b4b57cd BJ |
93 | if (fp == 0) |
94 | return; | |
88a7a62a | 95 | u.u_error = solisten((struct socket *)fp->f_data, uap->backlog); |
cf012934 BJ |
96 | } |
97 | ||
f4d2893a MK |
98 | #ifdef COMPAT_43 |
99 | accept() | |
100 | { | |
101 | accept1(0); | |
102 | } | |
103 | ||
104 | oaccept() | |
105 | { | |
106 | accept1(1); | |
107 | } | |
108 | ||
109 | accept1(compat_43) | |
110 | #else | |
cf012934 | 111 | accept() |
f4d2893a | 112 | #endif |
cf012934 BJ |
113 | { |
114 | register struct a { | |
115 | int s; | |
116 | caddr_t name; | |
117 | int *anamelen; | |
cf012934 | 118 | } *uap = (struct a *)u.u_ap; |
0c9a45f0 | 119 | struct file *fp; |
cf012934 | 120 | struct mbuf *nam; |
cf012934 BJ |
121 | int namelen; |
122 | int s; | |
123 | register struct socket *so; | |
124 | ||
125 | if (uap->name == 0) | |
126 | goto noname; | |
127f7d76 SL |
127 | u.u_error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen, |
128 | sizeof (namelen)); | |
129 | if (u.u_error) | |
cf012934 | 130 | return; |
b32450f4 | 131 | if (useracc((caddr_t)uap->name, (u_int)namelen, B_WRITE) == 0) { |
cf012934 BJ |
132 | u.u_error = EFAULT; |
133 | return; | |
134 | } | |
135 | noname: | |
88a7a62a | 136 | fp = getsock(uap->s); |
cf012934 | 137 | if (fp == 0) |
66f52238 | 138 | return; |
2b4b57cd | 139 | s = splnet(); |
88a7a62a | 140 | so = (struct socket *)fp->f_data; |
4147b3f6 BJ |
141 | if ((so->so_options & SO_ACCEPTCONN) == 0) { |
142 | u.u_error = EINVAL; | |
143 | splx(s); | |
66f52238 | 144 | return; |
4147b3f6 BJ |
145 | } |
146 | if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { | |
2b4b57cd BJ |
147 | u.u_error = EWOULDBLOCK; |
148 | splx(s); | |
66f52238 | 149 | return; |
2b4b57cd | 150 | } |
4147b3f6 | 151 | while (so->so_qlen == 0 && so->so_error == 0) { |
62229532 BJ |
152 | if (so->so_state & SS_CANTRCVMORE) { |
153 | so->so_error = ECONNABORTED; | |
154 | break; | |
155 | } | |
d08c5322 | 156 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
62229532 | 157 | } |
f269ef23 BJ |
158 | if (so->so_error) { |
159 | u.u_error = so->so_error; | |
f4ed5810 | 160 | so->so_error = 0; |
f269ef23 | 161 | splx(s); |
66f52238 | 162 | return; |
f269ef23 | 163 | } |
0c9a45f0 | 164 | if (u.u_error = falloc(&fp, &u.u_r.r_val1)) { |
2b4b57cd | 165 | splx(s); |
66f52238 | 166 | return; |
cf012934 BJ |
167 | } |
168 | { struct socket *aso = so->so_q; | |
169 | if (soqremque(aso, 1) == 0) | |
170 | panic("accept"); | |
171 | so = aso; | |
2b4b57cd | 172 | } |
4147b3f6 BJ |
173 | fp->f_type = DTYPE_SOCKET; |
174 | fp->f_flag = FREAD|FWRITE; | |
88a7a62a SL |
175 | fp->f_ops = &socketops; |
176 | fp->f_data = (caddr_t)so; | |
cce93e4b | 177 | nam = m_get(M_WAIT, MT_SONAME); |
66f52238 | 178 | (void) soaccept(so, nam); |
cf012934 | 179 | if (uap->name) { |
f4d2893a MK |
180 | #ifdef COMPAT_43 |
181 | if (compat_43) | |
182 | mtod(nam, struct osockaddr *)->sa_family = | |
183 | mtod(nam, struct sockaddr *)->sa_family; | |
184 | #endif | |
cf012934 BJ |
185 | if (namelen > nam->m_len) |
186 | namelen = nam->m_len; | |
187 | /* SHOULD COPY OUT A CHAIN HERE */ | |
b32450f4 BJ |
188 | (void) copyout(mtod(nam, caddr_t), (caddr_t)uap->name, |
189 | (u_int)namelen); | |
190 | (void) copyout((caddr_t)&namelen, (caddr_t)uap->anamelen, | |
cf012934 BJ |
191 | sizeof (*uap->anamelen)); |
192 | } | |
193 | m_freem(nam); | |
2b4b57cd | 194 | splx(s); |
ae921915 BJ |
195 | } |
196 | ||
cf012934 | 197 | connect() |
c8c7dd0e BJ |
198 | { |
199 | register struct a { | |
cf012934 BJ |
200 | int s; |
201 | caddr_t name; | |
202 | int namelen; | |
c8c7dd0e | 203 | } *uap = (struct a *)u.u_ap; |
c8c7dd0e BJ |
204 | register struct file *fp; |
205 | register struct socket *so; | |
cf012934 | 206 | struct mbuf *nam; |
c8c7dd0e BJ |
207 | int s; |
208 | ||
88a7a62a | 209 | fp = getsock(uap->s); |
c8c7dd0e BJ |
210 | if (fp == 0) |
211 | return; | |
88a7a62a | 212 | so = (struct socket *)fp->f_data; |
a7a77c02 MK |
213 | if ((so->so_state & SS_NBIO) && |
214 | (so->so_state & SS_ISCONNECTING)) { | |
6222acc3 | 215 | u.u_error = EALREADY; |
a7a77c02 MK |
216 | return; |
217 | } | |
98447d3f | 218 | u.u_error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME); |
c8c7dd0e BJ |
219 | if (u.u_error) |
220 | return; | |
66f52238 | 221 | u.u_error = soconnect(so, nam); |
cf012934 BJ |
222 | if (u.u_error) |
223 | goto bad; | |
6222acc3 MK |
224 | if ((so->so_state & SS_NBIO) && |
225 | (so->so_state & SS_ISCONNECTING)) { | |
226 | u.u_error = EINPROGRESS; | |
227 | m_freem(nam); | |
228 | return; | |
229 | } | |
c8c7dd0e | 230 | s = splnet(); |
88a7a62a SL |
231 | if (setjmp(&u.u_qsave)) { |
232 | if (u.u_error == 0) | |
233 | u.u_error = EINTR; | |
234 | goto bad2; | |
c8c7dd0e | 235 | } |
cc15ab5d | 236 | while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) |
c8c7dd0e BJ |
237 | sleep((caddr_t)&so->so_timeo, PZERO+1); |
238 | u.u_error = so->so_error; | |
cc15ab5d | 239 | so->so_error = 0; |
88a7a62a | 240 | bad2: |
cc15ab5d | 241 | splx(s); |
cf012934 | 242 | bad: |
6750daae | 243 | so->so_state &= ~SS_ISCONNECTING; |
cf012934 | 244 | m_freem(nam); |
c8c7dd0e BJ |
245 | } |
246 | ||
cf012934 BJ |
247 | socketpair() |
248 | { | |
5a48956d SL |
249 | register struct a { |
250 | int domain; | |
251 | int type; | |
252 | int protocol; | |
253 | int *rsv; | |
254 | } *uap = (struct a *)u.u_ap; | |
0c9a45f0 | 255 | struct file *fp1, *fp2; |
5a48956d | 256 | struct socket *so1, *so2; |
0c9a45f0 | 257 | int fd, sv[2]; |
cf012934 | 258 | |
5a48956d SL |
259 | if (useracc((caddr_t)uap->rsv, 2 * sizeof (int), B_WRITE) == 0) { |
260 | u.u_error = EFAULT; | |
261 | return; | |
262 | } | |
263 | u.u_error = socreate(uap->domain, &so1, uap->type, uap->protocol); | |
264 | if (u.u_error) | |
265 | return; | |
266 | u.u_error = socreate(uap->domain, &so2, uap->type, uap->protocol); | |
267 | if (u.u_error) | |
b242cf10 | 268 | goto free1; |
0c9a45f0 | 269 | if (u.u_error = falloc(&fp1, &fd)) |
5a48956d | 270 | goto free2; |
0c9a45f0 | 271 | sv[0] = fd; |
5a48956d SL |
272 | fp1->f_flag = FREAD|FWRITE; |
273 | fp1->f_type = DTYPE_SOCKET; | |
274 | fp1->f_ops = &socketops; | |
275 | fp1->f_data = (caddr_t)so1; | |
0c9a45f0 | 276 | if (u.u_error = falloc(&fp2, &fd)) |
5a48956d SL |
277 | goto free3; |
278 | fp2->f_flag = FREAD|FWRITE; | |
279 | fp2->f_type = DTYPE_SOCKET; | |
280 | fp2->f_ops = &socketops; | |
281 | fp2->f_data = (caddr_t)so2; | |
0c9a45f0 | 282 | sv[1] = fd; |
5a48956d SL |
283 | u.u_error = soconnect2(so1, so2); |
284 | if (u.u_error) | |
285 | goto free4; | |
33446404 MK |
286 | if (uap->type == SOCK_DGRAM) { |
287 | /* | |
288 | * Datagram socket connection is asymmetric. | |
289 | */ | |
290 | u.u_error = soconnect2(so2, so1); | |
291 | if (u.u_error) | |
292 | goto free4; | |
293 | } | |
5a48956d | 294 | (void) copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int)); |
0c9a45f0 KM |
295 | u.u_r.r_val1 = sv[0]; |
296 | u.u_r.r_val2 = sv[1]; | |
5a48956d SL |
297 | return; |
298 | free4: | |
0c9a45f0 | 299 | crfree(fp2->f_cred); |
5a48956d SL |
300 | fp2->f_count = 0; |
301 | u.u_ofile[sv[1]] = 0; | |
302 | free3: | |
0c9a45f0 | 303 | crfree(fp1->f_cred); |
5a48956d SL |
304 | fp1->f_count = 0; |
305 | u.u_ofile[sv[0]] = 0; | |
306 | free2: | |
8011f5df | 307 | (void)soclose(so2); |
b242cf10 | 308 | free1: |
8011f5df | 309 | (void)soclose(so1); |
cf012934 BJ |
310 | } |
311 | ||
312 | sendto() | |
c8c7dd0e BJ |
313 | { |
314 | register struct a { | |
cf012934 BJ |
315 | int s; |
316 | caddr_t buf; | |
317 | int len; | |
318 | int flags; | |
319 | caddr_t to; | |
320 | int tolen; | |
c8c7dd0e | 321 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 322 | struct msghdr msg; |
d3d550b5 | 323 | struct iovec aiov; |
c8c7dd0e | 324 | |
88a7a62a SL |
325 | msg.msg_name = uap->to; |
326 | msg.msg_namelen = uap->tolen; | |
327 | msg.msg_iov = &aiov; | |
328 | msg.msg_iovlen = 1; | |
cf012934 BJ |
329 | aiov.iov_base = uap->buf; |
330 | aiov.iov_len = uap->len; | |
88a7a62a | 331 | msg.msg_accrights = 0; |
6d47a3da | 332 | msg.msg_control = 0; |
88a7a62a | 333 | sendit(uap->s, &msg, uap->flags); |
c8c7dd0e BJ |
334 | } |
335 | ||
6d47a3da | 336 | #ifdef COMPAT_43 |
f4d2893a | 337 | |
6d47a3da | 338 | osend() |
cc15ab5d BJ |
339 | { |
340 | register struct a { | |
cf012934 BJ |
341 | int s; |
342 | caddr_t buf; | |
343 | int len; | |
344 | int flags; | |
cc15ab5d | 345 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 346 | struct msghdr msg; |
a6b6f679 | 347 | struct iovec aiov; |
cc15ab5d | 348 | |
88a7a62a SL |
349 | msg.msg_name = 0; |
350 | msg.msg_namelen = 0; | |
351 | msg.msg_iov = &aiov; | |
352 | msg.msg_iovlen = 1; | |
cf012934 BJ |
353 | aiov.iov_base = uap->buf; |
354 | aiov.iov_len = uap->len; | |
88a7a62a | 355 | msg.msg_accrights = 0; |
6d47a3da | 356 | msg.msg_control = 0; |
88a7a62a SL |
357 | sendit(uap->s, &msg, uap->flags); |
358 | } | |
359 | ||
6d47a3da MK |
360 | osendmsg() |
361 | { | |
362 | register struct a { | |
363 | int s; | |
364 | caddr_t msg; | |
365 | int flags; | |
366 | } *uap = (struct a *)u.u_ap; | |
367 | struct msghdr msg; | |
368 | struct iovec aiov[MSG_MAXIOVLEN]; | |
369 | ||
370 | u.u_error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr)); | |
371 | if (u.u_error) | |
372 | return; | |
373 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
374 | u.u_error = EMSGSIZE; | |
375 | return; | |
376 | } | |
377 | u.u_error = copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, | |
378 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); | |
379 | if (u.u_error) | |
380 | return; | |
381 | msg.msg_control = 0; | |
382 | msg.msg_controllen = 0; | |
383 | sendit(uap->s, &msg, uap->flags); | |
384 | } | |
385 | #endif | |
386 | ||
88a7a62a SL |
387 | sendmsg() |
388 | { | |
389 | register struct a { | |
390 | int s; | |
391 | caddr_t msg; | |
392 | int flags; | |
393 | } *uap = (struct a *)u.u_ap; | |
394 | struct msghdr msg; | |
395 | struct iovec aiov[MSG_MAXIOVLEN]; | |
396 | ||
397 | u.u_error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)); | |
398 | if (u.u_error) | |
399 | return; | |
400 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
401 | u.u_error = EMSGSIZE; | |
cf012934 BJ |
402 | return; |
403 | } | |
6d47a3da | 404 | u.u_error = copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, |
88a7a62a | 405 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); |
cf012934 BJ |
406 | if (u.u_error) |
407 | return; | |
88a7a62a | 408 | msg.msg_iov = aiov; |
88a7a62a SL |
409 | sendit(uap->s, &msg, uap->flags); |
410 | } | |
411 | ||
412 | sendit(s, mp, flags) | |
413 | int s; | |
414 | register struct msghdr *mp; | |
415 | int flags; | |
416 | { | |
417 | register struct file *fp; | |
418 | struct uio auio; | |
419 | register struct iovec *iov; | |
420 | register int i; | |
6d47a3da | 421 | struct mbuf *to, *rights, *control; |
88a7a62a SL |
422 | int len; |
423 | ||
424 | fp = getsock(s); | |
425 | if (fp == 0) | |
426 | return; | |
427 | auio.uio_iov = mp->msg_iov; | |
428 | auio.uio_iovcnt = mp->msg_iovlen; | |
c41770c0 | 429 | auio.uio_segflg = UIO_USERSPACE; |
c4ec2128 | 430 | auio.uio_rw = UIO_WRITE; |
88a7a62a SL |
431 | auio.uio_offset = 0; /* XXX */ |
432 | auio.uio_resid = 0; | |
433 | iov = mp->msg_iov; | |
125c8f95 | 434 | for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
88a7a62a SL |
435 | if (iov->iov_len < 0) { |
436 | u.u_error = EINVAL; | |
437 | return; | |
438 | } | |
0f6422b0 MK |
439 | if (iov->iov_len == 0) |
440 | continue; | |
88a7a62a SL |
441 | if (useracc(iov->iov_base, (u_int)iov->iov_len, B_READ) == 0) { |
442 | u.u_error = EFAULT; | |
443 | return; | |
444 | } | |
445 | auio.uio_resid += iov->iov_len; | |
88a7a62a SL |
446 | } |
447 | if (mp->msg_name) { | |
448 | u.u_error = | |
98447d3f | 449 | sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME); |
88a7a62a SL |
450 | if (u.u_error) |
451 | return; | |
452 | } else | |
453 | to = 0; | |
454 | if (mp->msg_accrights) { | |
455 | u.u_error = | |
98447d3f MK |
456 | sockargs(&rights, mp->msg_accrights, mp->msg_accrightslen, |
457 | MT_RIGHTS); | |
88a7a62a SL |
458 | if (u.u_error) |
459 | goto bad; | |
460 | } else | |
461 | rights = 0; | |
6d47a3da MK |
462 | if (mp->msg_control) { |
463 | u.u_error = | |
464 | sockargs(&control, mp->msg_control, mp->msg_controllen, | |
465 | MT_CONTROL); | |
466 | if (u.u_error) | |
467 | goto bad; | |
468 | } else | |
469 | control = 0; | |
88a7a62a | 470 | len = auio.uio_resid; |
6d47a3da MK |
471 | if (setjmp(&u.u_qsave)) { /* XXX */ |
472 | if (auio.uio_resid == len) { | |
473 | if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) | |
474 | u.u_error = EINTR; | |
475 | else | |
476 | u.u_eosys = RESTARTSYS; | |
477 | } | |
478 | } else | |
479 | u.u_error = sosend((struct socket *)fp->f_data, to, &auio, | |
480 | flags, rights, control); | |
88a7a62a | 481 | u.u_r.r_val1 = len - auio.uio_resid; |
6d47a3da | 482 | bad: |
88a7a62a SL |
483 | if (rights) |
484 | m_freem(rights); | |
88a7a62a SL |
485 | if (to) |
486 | m_freem(to); | |
6d47a3da MK |
487 | if (control) |
488 | m_freem(control); | |
cf012934 BJ |
489 | } |
490 | ||
f4d2893a MK |
491 | #ifdef COMPAT_43 |
492 | recvfrom() | |
493 | { | |
494 | recvfrom1(0); | |
495 | } | |
496 | ||
497 | orecvfrom() | |
498 | { | |
499 | recvfrom1(1); | |
500 | } | |
501 | ||
502 | recvfrom1(compat_43) | |
503 | { /* vi will want an extra } to be happy! */ | |
504 | #else | |
cf012934 BJ |
505 | recvfrom() |
506 | { | |
f4d2893a MK |
507 | int compat_43 = 0; |
508 | #endif | |
cf012934 BJ |
509 | register struct a { |
510 | int s; | |
511 | caddr_t buf; | |
512 | int len; | |
513 | int flags; | |
514 | caddr_t from; | |
515 | int *fromlenaddr; | |
516 | } *uap = (struct a *)u.u_ap; | |
88a7a62a | 517 | struct msghdr msg; |
cf012934 | 518 | struct iovec aiov; |
88a7a62a | 519 | int len; |
cf012934 | 520 | |
6d47a3da MK |
521 | if (uap->fromlenaddr) { |
522 | u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&len, | |
523 | sizeof (len)); | |
524 | if (u.u_error) | |
525 | return; | |
526 | } else | |
527 | len = 0; | |
88a7a62a SL |
528 | msg.msg_name = uap->from; |
529 | msg.msg_namelen = len; | |
530 | msg.msg_iov = &aiov; | |
531 | msg.msg_iovlen = 1; | |
cf012934 BJ |
532 | aiov.iov_base = uap->buf; |
533 | aiov.iov_len = uap->len; | |
88a7a62a | 534 | msg.msg_accrights = 0; |
6d47a3da MK |
535 | msg.msg_control = 0; |
536 | msg.msg_flags = uap->flags; | |
a2aebb63 | 537 | recvit(uap->s, &msg, (caddr_t)uap->fromlenaddr, (caddr_t)0, compat_43); |
cf012934 | 538 | } |
6d47a3da | 539 | #ifdef COMPAT_43 |
6d47a3da | 540 | orecv() |
cf012934 BJ |
541 | { |
542 | register struct a { | |
543 | int s; | |
544 | caddr_t buf; | |
545 | int len; | |
546 | int flags; | |
547 | } *uap = (struct a *)u.u_ap; | |
88a7a62a | 548 | struct msghdr msg; |
cf012934 BJ |
549 | struct iovec aiov; |
550 | ||
88a7a62a SL |
551 | msg.msg_name = 0; |
552 | msg.msg_namelen = 0; | |
553 | msg.msg_iov = &aiov; | |
554 | msg.msg_iovlen = 1; | |
cf012934 BJ |
555 | aiov.iov_base = uap->buf; |
556 | aiov.iov_len = uap->len; | |
88a7a62a | 557 | msg.msg_accrights = 0; |
6d47a3da MK |
558 | msg.msg_control = 0; |
559 | msg.msg_flags = uap->flags; | |
a2aebb63 | 560 | recvit(uap->s, &msg, (caddr_t)0, (caddr_t)0, 0); |
6d47a3da MK |
561 | } |
562 | ||
563 | orecvmsg() | |
564 | { | |
565 | register struct a { | |
566 | int s; | |
567 | struct omsghdr *msg; | |
568 | int flags; | |
569 | } *uap = (struct a *)u.u_ap; | |
570 | struct msghdr msg; | |
571 | struct iovec aiov[MSG_MAXIOVLEN]; | |
572 | ||
573 | u.u_error = copyin((caddr_t)uap->msg, (caddr_t)&msg, | |
574 | sizeof (struct omsghdr)); | |
575 | if (u.u_error) | |
576 | return; | |
577 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
578 | u.u_error = EMSGSIZE; | |
579 | return; | |
580 | } | |
581 | msg.msg_control = 0; | |
582 | msg.msg_flags = uap->flags; | |
583 | u.u_error = copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, | |
584 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); | |
585 | if (u.u_error) | |
586 | return; | |
587 | msg.msg_iov = aiov; | |
588 | if (msg.msg_accrights) | |
589 | if (useracc((caddr_t)msg.msg_accrights, | |
590 | (unsigned)msg.msg_accrightslen, B_WRITE) == 0) { | |
591 | u.u_error = EFAULT; | |
592 | return; | |
593 | } | |
594 | ||
595 | recvit(uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, | |
a2aebb63 | 596 | (caddr_t)&uap->msg->msg_accrightslen, /* compat_43 */1); |
cf012934 | 597 | } |
6d47a3da | 598 | #endif |
cf012934 | 599 | |
88a7a62a | 600 | recvmsg() |
cf012934 | 601 | { |
88a7a62a SL |
602 | register struct a { |
603 | int s; | |
604 | struct msghdr *msg; | |
605 | int flags; | |
606 | } *uap = (struct a *)u.u_ap; | |
607 | struct msghdr msg; | |
f4d2893a | 608 | struct iovec aiov[MSG_MAXIOVLEN], *uiov; |
cf012934 | 609 | |
88a7a62a SL |
610 | u.u_error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg)); |
611 | if (u.u_error) | |
612 | return; | |
613 | if ((u_int)msg.msg_iovlen >= sizeof (aiov) / sizeof (aiov[0])) { | |
614 | u.u_error = EMSGSIZE; | |
615 | return; | |
616 | } | |
6d47a3da MK |
617 | msg.msg_flags = uap->flags; |
618 | u.u_error = copyin((caddr_t)msg.msg_iov, (caddr_t)aiov, | |
88a7a62a SL |
619 | (unsigned)(msg.msg_iovlen * sizeof (aiov[0]))); |
620 | if (u.u_error) | |
621 | return; | |
f4d2893a | 622 | uiov = msg.msg_iov; |
88a7a62a SL |
623 | msg.msg_iov = aiov; |
624 | if (msg.msg_accrights) | |
625 | if (useracc((caddr_t)msg.msg_accrights, | |
626 | (unsigned)msg.msg_accrightslen, B_WRITE) == 0) { | |
627 | u.u_error = EFAULT; | |
628 | return; | |
629 | } | |
6d47a3da MK |
630 | if (msg.msg_control) |
631 | if (useracc((caddr_t)msg.msg_control, | |
632 | (unsigned)msg.msg_controllen, B_WRITE) == 0) { | |
633 | u.u_error = EFAULT; | |
634 | return; | |
635 | } | |
a2aebb63 | 636 | recvit(uap->s, &msg, (caddr_t)0, (caddr_t)0, 0); |
f4d2893a MK |
637 | msg.msg_iov = uiov; |
638 | u.u_error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg)); | |
cf012934 BJ |
639 | } |
640 | ||
c4ec2128 | 641 | /* ARGSUSED */ |
a2aebb63 | 642 | recvit(s, mp, namelenp, rightslenp, compat_43) |
f4d2893a | 643 | int s, compat_43; |
88a7a62a | 644 | register struct msghdr *mp; |
a2aebb63 | 645 | caddr_t namelenp, rightslenp; |
cf012934 | 646 | { |
88a7a62a SL |
647 | register struct file *fp; |
648 | struct uio auio; | |
649 | register struct iovec *iov; | |
650 | register int i; | |
88a7a62a | 651 | int len; |
6d47a3da | 652 | struct mbuf *from = 0, *rights = 0, *control = 0; |
88a7a62a SL |
653 | |
654 | fp = getsock(s); | |
655 | if (fp == 0) | |
656 | return; | |
657 | auio.uio_iov = mp->msg_iov; | |
658 | auio.uio_iovcnt = mp->msg_iovlen; | |
c41770c0 | 659 | auio.uio_segflg = UIO_USERSPACE; |
c4ec2128 | 660 | auio.uio_rw = UIO_READ; |
88a7a62a SL |
661 | auio.uio_offset = 0; /* XXX */ |
662 | auio.uio_resid = 0; | |
663 | iov = mp->msg_iov; | |
125c8f95 | 664 | for (i = 0; i < mp->msg_iovlen; i++, iov++) { |
88a7a62a SL |
665 | if (iov->iov_len < 0) { |
666 | u.u_error = EINVAL; | |
667 | return; | |
668 | } | |
0f6422b0 MK |
669 | if (iov->iov_len == 0) |
670 | continue; | |
88a7a62a SL |
671 | if (useracc(iov->iov_base, (u_int)iov->iov_len, B_WRITE) == 0) { |
672 | u.u_error = EFAULT; | |
673 | return; | |
674 | } | |
675 | auio.uio_resid += iov->iov_len; | |
88a7a62a SL |
676 | } |
677 | len = auio.uio_resid; | |
6d47a3da MK |
678 | if (setjmp(&u.u_qsave)) { /* XXX */ |
679 | if (auio.uio_resid == len) { | |
680 | if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) | |
681 | u.u_error = EINTR; | |
682 | else | |
683 | u.u_eosys = RESTARTSYS; | |
684 | } | |
685 | } else | |
686 | u.u_error = soreceive((struct socket *)fp->f_data, &from, &auio, | |
687 | &mp->msg_flags, &rights, &control); | |
88a7a62a SL |
688 | u.u_r.r_val1 = len - auio.uio_resid; |
689 | if (mp->msg_name) { | |
690 | len = mp->msg_namelen; | |
691 | if (len <= 0 || from == 0) | |
692 | len = 0; | |
693 | else { | |
f4d2893a MK |
694 | #ifdef COMPAT_43 |
695 | if (compat_43) | |
696 | mtod(from, struct osockaddr *)->sa_family = | |
697 | mtod(from, struct sockaddr *)->sa_family; | |
698 | #endif | |
699 | if (len > from->m_len) /* ??? */ | |
88a7a62a | 700 | len = from->m_len; |
6d47a3da | 701 | (void) copyout(mtod(from, caddr_t), |
88a7a62a SL |
702 | (caddr_t)mp->msg_name, (unsigned)len); |
703 | } | |
a2aebb63 | 704 | mp->msg_namelen = len; |
6d47a3da MK |
705 | if (namelenp) |
706 | (void) copyout((caddr_t)&len, namelenp, sizeof (int)); | |
88a7a62a SL |
707 | } |
708 | if (mp->msg_accrights) { | |
709 | len = mp->msg_accrightslen; | |
710 | if (len <= 0 || rights == 0) | |
711 | len = 0; | |
712 | else { | |
713 | if (len > rights->m_len) | |
714 | len = rights->m_len; | |
715 | (void) copyout((caddr_t)mtod(rights, caddr_t), | |
716 | (caddr_t)mp->msg_accrights, (unsigned)len); | |
717 | } | |
a2aebb63 | 718 | mp->msg_accrightslen = len; |
6d47a3da MK |
719 | if (rightslenp) |
720 | (void) copyout((caddr_t)&len, rightslenp, sizeof (int)); | |
721 | } | |
722 | if (mp->msg_control) { | |
723 | len = mp->msg_controllen; | |
724 | if (len <= 0 || control == 0) | |
725 | len = 0; | |
726 | else { | |
727 | if (len >= control->m_len) | |
728 | len = control->m_len; | |
729 | else | |
730 | mp->msg_flags |= MSG_CTRUNC; | |
731 | (void) copyout((caddr_t)mtod(control, caddr_t), | |
732 | (caddr_t)mp->msg_control, (unsigned)len); | |
733 | } | |
a2aebb63 | 734 | mp->msg_controllen = len; |
88a7a62a SL |
735 | } |
736 | if (rights) | |
737 | m_freem(rights); | |
738 | if (from) | |
739 | m_freem(from); | |
6d47a3da MK |
740 | if (control) |
741 | m_freem(control); | |
cf012934 BJ |
742 | } |
743 | ||
744 | shutdown() | |
745 | { | |
6ef233bf SL |
746 | struct a { |
747 | int s; | |
748 | int how; | |
749 | } *uap = (struct a *)u.u_ap; | |
750 | struct file *fp; | |
cf012934 | 751 | |
88a7a62a | 752 | fp = getsock(uap->s); |
6ef233bf SL |
753 | if (fp == 0) |
754 | return; | |
88a7a62a | 755 | u.u_error = soshutdown((struct socket *)fp->f_data, uap->how); |
cf012934 BJ |
756 | } |
757 | ||
66f52238 SL |
758 | setsockopt() |
759 | { | |
760 | struct a { | |
761 | int s; | |
762 | int level; | |
763 | int name; | |
764 | caddr_t val; | |
765 | int valsize; | |
766 | } *uap = (struct a *)u.u_ap; | |
767 | struct file *fp; | |
d2cba8de | 768 | struct mbuf *m = NULL; |
66f52238 | 769 | |
88a7a62a | 770 | fp = getsock(uap->s); |
66f52238 SL |
771 | if (fp == 0) |
772 | return; | |
66f52238 SL |
773 | if (uap->valsize > MLEN) { |
774 | u.u_error = EINVAL; | |
775 | return; | |
776 | } | |
d2cba8de SL |
777 | if (uap->val) { |
778 | m = m_get(M_WAIT, MT_SOOPTS); | |
7c52d753 | 779 | if (m == NULL) { |
d2cba8de SL |
780 | u.u_error = ENOBUFS; |
781 | return; | |
782 | } | |
88a7a62a SL |
783 | u.u_error = |
784 | copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize); | |
61ec2127 SL |
785 | if (u.u_error) { |
786 | (void) m_free(m); | |
787 | return; | |
788 | } | |
d2cba8de | 789 | m->m_len = uap->valsize; |
66f52238 | 790 | } |
88a7a62a SL |
791 | u.u_error = |
792 | sosetopt((struct socket *)fp->f_data, uap->level, uap->name, m); | |
66f52238 SL |
793 | } |
794 | ||
795 | getsockopt() | |
796 | { | |
797 | struct a { | |
798 | int s; | |
799 | int level; | |
800 | int name; | |
801 | caddr_t val; | |
802 | int *avalsize; | |
803 | } *uap = (struct a *)u.u_ap; | |
804 | struct file *fp; | |
d2cba8de | 805 | struct mbuf *m = NULL; |
66f52238 SL |
806 | int valsize; |
807 | ||
88a7a62a | 808 | fp = getsock(uap->s); |
66f52238 SL |
809 | if (fp == 0) |
810 | return; | |
d2cba8de SL |
811 | if (uap->val) { |
812 | u.u_error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize, | |
813 | sizeof (valsize)); | |
814 | if (u.u_error) | |
815 | return; | |
61ec2127 SL |
816 | } else |
817 | valsize = 0; | |
88a7a62a | 818 | u.u_error = |
61ec2127 | 819 | sogetopt((struct socket *)fp->f_data, uap->level, uap->name, &m); |
66f52238 SL |
820 | if (u.u_error) |
821 | goto bad; | |
61ec2127 | 822 | if (uap->val && valsize && m != NULL) { |
d2cba8de SL |
823 | if (valsize > m->m_len) |
824 | valsize = m->m_len; | |
825 | u.u_error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize); | |
826 | if (u.u_error) | |
827 | goto bad; | |
828 | u.u_error = copyout((caddr_t)&valsize, (caddr_t)uap->avalsize, | |
829 | sizeof (valsize)); | |
830 | } | |
66f52238 | 831 | bad: |
d2cba8de SL |
832 | if (m != NULL) |
833 | (void) m_free(m); | |
66f52238 SL |
834 | } |
835 | ||
cf012934 BJ |
836 | pipe() |
837 | { | |
0c9a45f0 | 838 | struct file *rf, *wf; |
cf012934 | 839 | struct socket *rso, *wso; |
0c9a45f0 | 840 | int fd, r; |
cf012934 | 841 | |
88a7a62a | 842 | u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0); |
2b4b57cd BJ |
843 | if (u.u_error) |
844 | return; | |
88a7a62a | 845 | u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0); |
cf012934 | 846 | if (u.u_error) |
b242cf10 | 847 | goto free1; |
0c9a45f0 | 848 | if (u.u_error = falloc(&rf, &fd)) |
cf012934 | 849 | goto free2; |
0c9a45f0 | 850 | u.u_r.r_val1 = fd; |
cf012934 BJ |
851 | rf->f_flag = FREAD; |
852 | rf->f_type = DTYPE_SOCKET; | |
88a7a62a SL |
853 | rf->f_ops = &socketops; |
854 | rf->f_data = (caddr_t)rso; | |
0c9a45f0 | 855 | if (u.u_error = falloc(&wf, &fd)) |
cf012934 BJ |
856 | goto free3; |
857 | wf->f_flag = FWRITE; | |
858 | wf->f_type = DTYPE_SOCKET; | |
88a7a62a SL |
859 | wf->f_ops = &socketops; |
860 | wf->f_data = (caddr_t)wso; | |
0c9a45f0 | 861 | u.u_r.r_val2 = fd; |
d97afdcc | 862 | if (u.u_error = unp_connect2(wso, rso)) |
cf012934 | 863 | goto free4; |
9c58d471 MK |
864 | wso->so_state |= SS_CANTRCVMORE; |
865 | rso->so_state |= SS_CANTSENDMORE; | |
cf012934 BJ |
866 | return; |
867 | free4: | |
868 | wf->f_count = 0; | |
869 | u.u_ofile[u.u_r.r_val2] = 0; | |
870 | free3: | |
871 | rf->f_count = 0; | |
c4ec2128 | 872 | u.u_ofile[u.u_r.r_val1] = 0; |
cf012934 | 873 | free2: |
8011f5df | 874 | (void)soclose(wso); |
b242cf10 | 875 | free1: |
8011f5df | 876 | (void)soclose(rso); |
cc15ab5d | 877 | } |
a3076b07 BJ |
878 | |
879 | /* | |
70f2eac5 | 880 | * Get socket name. |
a3076b07 | 881 | */ |
f4d2893a MK |
882 | #ifdef COMPAT_43 |
883 | getsockname() | |
884 | { | |
885 | getsockname1(0); | |
886 | } | |
887 | ||
888 | ogetsockname() | |
889 | { | |
890 | getsockname1(1); | |
891 | } | |
892 | ||
893 | getsockname1(compat_43) | |
894 | #else | |
70f2eac5 | 895 | getsockname() |
f4d2893a | 896 | #endif |
a3076b07 BJ |
897 | { |
898 | register struct a { | |
899 | int fdes; | |
70f2eac5 SL |
900 | caddr_t asa; |
901 | int *alen; | |
a3076b07 BJ |
902 | } *uap = (struct a *)u.u_ap; |
903 | register struct file *fp; | |
05d69517 | 904 | register struct socket *so; |
cf012934 | 905 | struct mbuf *m; |
70f2eac5 | 906 | int len; |
a3076b07 | 907 | |
88a7a62a | 908 | fp = getsock(uap->fdes); |
a3076b07 BJ |
909 | if (fp == 0) |
910 | return; | |
70f2eac5 SL |
911 | u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); |
912 | if (u.u_error) | |
913 | return; | |
88a7a62a | 914 | so = (struct socket *)fp->f_data; |
cce93e4b | 915 | m = m_getclr(M_WAIT, MT_SONAME); |
7c52d753 SL |
916 | if (m == NULL) { |
917 | u.u_error = ENOBUFS; | |
918 | return; | |
919 | } | |
70f2eac5 SL |
920 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0); |
921 | if (u.u_error) | |
922 | goto bad; | |
923 | if (len > m->m_len) | |
924 | len = m->m_len; | |
f4d2893a MK |
925 | #ifdef COMPAT_43 |
926 | if (compat_43) | |
927 | mtod(m, struct osockaddr *)->sa_family = | |
928 | mtod(m, struct sockaddr *)->sa_family; | |
929 | #endif | |
70f2eac5 | 930 | u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); |
f4d2893a MK |
931 | if (u.u_error == 0) |
932 | u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, | |
933 | sizeof (len)); | |
cf012934 BJ |
934 | bad: |
935 | m_freem(m); | |
936 | } | |
937 | ||
f4d2893a MK |
938 | /* |
939 | * Get name of peer for connected socket. | |
940 | */ | |
6d47a3da | 941 | #ifdef COMPAT_43 |
f4d2893a | 942 | getpeername() |
6d47a3da | 943 | { |
f4d2893a | 944 | getpeername1(0); |
6d47a3da | 945 | } |
6d47a3da | 946 | |
f4d2893a MK |
947 | ogetpeername() |
948 | { | |
949 | getpeername1(1); | |
950 | } | |
951 | ||
952 | getpeername1(compat_43) | |
953 | #else | |
a7343092 | 954 | getpeername() |
f4d2893a | 955 | #endif |
a7343092 SL |
956 | { |
957 | register struct a { | |
958 | int fdes; | |
959 | caddr_t asa; | |
960 | int *alen; | |
961 | } *uap = (struct a *)u.u_ap; | |
962 | register struct file *fp; | |
963 | register struct socket *so; | |
964 | struct mbuf *m; | |
965 | int len; | |
966 | ||
967 | fp = getsock(uap->fdes); | |
968 | if (fp == 0) | |
969 | return; | |
970 | so = (struct socket *)fp->f_data; | |
971 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
972 | u.u_error = ENOTCONN; | |
973 | return; | |
974 | } | |
975 | m = m_getclr(M_WAIT, MT_SONAME); | |
976 | if (m == NULL) { | |
977 | u.u_error = ENOBUFS; | |
978 | return; | |
979 | } | |
980 | u.u_error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); | |
981 | if (u.u_error) | |
982 | return; | |
983 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0); | |
984 | if (u.u_error) | |
985 | goto bad; | |
986 | if (len > m->m_len) | |
987 | len = m->m_len; | |
f4d2893a MK |
988 | #ifdef COMPAT_43 |
989 | if (compat_43) | |
990 | mtod(m, struct osockaddr *)->sa_family = | |
991 | mtod(m, struct sockaddr *)->sa_family; | |
992 | #endif | |
a7343092 SL |
993 | u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len); |
994 | if (u.u_error) | |
995 | goto bad; | |
996 | u.u_error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len)); | |
997 | bad: | |
998 | m_freem(m); | |
999 | } | |
1000 | ||
98447d3f | 1001 | sockargs(aname, name, namelen, type) |
cf012934 BJ |
1002 | struct mbuf **aname; |
1003 | caddr_t name; | |
98447d3f | 1004 | int namelen, type; |
cf012934 BJ |
1005 | { |
1006 | register struct mbuf *m; | |
127f7d76 | 1007 | int error; |
cf012934 | 1008 | |
7e4a3868 | 1009 | if ((u_int)namelen > MLEN) |
cf012934 | 1010 | return (EINVAL); |
98447d3f | 1011 | m = m_get(M_WAIT, type); |
7c52d753 SL |
1012 | if (m == NULL) |
1013 | return (ENOBUFS); | |
cf012934 | 1014 | m->m_len = namelen; |
127f7d76 SL |
1015 | error = copyin(name, mtod(m, caddr_t), (u_int)namelen); |
1016 | if (error) | |
cf012934 | 1017 | (void) m_free(m); |
127f7d76 SL |
1018 | else |
1019 | *aname = m; | |
a2aebb63 KS |
1020 | if (type == MT_SONAME) { |
1021 | register struct sockaddr *sa = mtod(m, struct sockaddr *); | |
f4d2893a | 1022 | #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN |
a2aebb63 KS |
1023 | if (sa->sa_family == 0 && sa->sa_len < AF_MAX) |
1024 | sa->sa_family = sa->sa_len; | |
f4d2893a | 1025 | #endif |
a2aebb63 KS |
1026 | sa->sa_len = namelen; |
1027 | } | |
127f7d76 | 1028 | return (error); |
cf012934 | 1029 | } |
88a7a62a SL |
1030 | |
1031 | struct file * | |
1032 | getsock(fdes) | |
1033 | int fdes; | |
1034 | { | |
1035 | register struct file *fp; | |
1036 | ||
c4ec2128 KM |
1037 | if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) { |
1038 | u.u_error = EBADF; | |
88a7a62a | 1039 | return (0); |
c4ec2128 | 1040 | } |
88a7a62a SL |
1041 | if (fp->f_type != DTYPE_SOCKET) { |
1042 | u.u_error = ENOTSOCK; | |
1043 | return (0); | |
1044 | } | |
1045 | return (fp); | |
1046 | } |