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