1 /*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)uipc_syscalls.c 8.6 (Berkeley) 02/14/95
8 */
9
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/filedesc.h>
13 #include <sys/proc.h>
14 #include <sys/file.h>
15 #include <sys/buf.h>
16 #include <sys/malloc.h>
17 #include <sys/mbuf.h>
18 #include <sys/protosw.h>
19 #include <sys/socket.h>
20 #include <sys/socketvar.h>
21 #ifdef KTRACE
22 #include <sys/ktrace.h>
23 #endif
24
25 #include <sys/mount.h>
26 #include <sys/syscallargs.h>
27
28 /*
29 * System call interface to the socket abstraction.
30 */
31 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
32 #define COMPAT_OLDSOCK
33 #endif
34
35 extern struct fileops socketops;
36
37 int
socket(p,uap,retval)38 socket(p, uap, retval)
39 struct proc *p;
40 register struct socket_args /* {
41 syscallarg(int) domain;
42 syscallarg(int) type;
43 syscallarg(int) protocol;
44 } */ *uap;
45 register_t *retval;
46 {
47 struct filedesc *fdp = p->p_fd;
48 struct socket *so;
49 struct file *fp;
50 int fd, error;
51
52 if (error = falloc(p, &fp, &fd))
53 return (error);
54 fp->f_flag = FREAD|FWRITE;
55 fp->f_type = DTYPE_SOCKET;
56 fp->f_ops = &socketops;
57 if (error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
58 SCARG(uap, protocol))) {
59 fdp->fd_ofiles[fd] = 0;
60 ffree(fp);
61 } else {
62 fp->f_data = (caddr_t)so;
63 *retval = fd;
64 }
65 return (error);
66 }
67
68 /* ARGSUSED */
69 int
bind(p,uap,retval)70 bind(p, uap, retval)
71 struct proc *p;
72 register struct bind_args /* {
73 syscallarg(int) s;
74 syscallarg(caddr_t) name;
75 syscallarg(int) namelen;
76 } */ *uap;
77 register_t *retval;
78 {
79 struct file *fp;
80 struct mbuf *nam;
81 int error;
82
83 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
84 return (error);
85 if (error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
86 MT_SONAME))
87 return (error);
88 error = sobind((struct socket *)fp->f_data, nam);
89 m_freem(nam);
90 return (error);
91 }
92
93 /* ARGSUSED */
94 int
listen(p,uap,retval)95 listen(p, uap, retval)
96 struct proc *p;
97 register struct listen_args /* {
98 syscallarg(int) s;
99 syscallarg(int) backlog;
100 } */ *uap;
101 register_t *retval;
102 {
103 struct file *fp;
104 int error;
105
106 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
107 return (error);
108 return (solisten((struct socket *)fp->f_data, SCARG(uap, backlog)));
109 }
110
111 #ifdef COMPAT_OLDSOCK
112 int
accept(p,uap,retval)113 accept(p, uap, retval)
114 struct proc *p;
115 struct accept_args /* {
116 syscallarg(int) s;
117 syscallarg(caddr_t) name;
118 syscallarg(int *) anamelen;
119 } */ *uap;
120 register_t *retval;
121 {
122
123 return (accept1(p, uap, retval, 0));
124 }
125
126 int
compat_43_accept(p,uap,retval)127 compat_43_accept(p, uap, retval)
128 struct proc *p;
129 struct accept_args /* {
130 syscallarg(int) s;
131 syscallarg(caddr_t) name;
132 syscallarg(int *) anamelen;
133 } */ *uap;
134 register_t *retval;
135 {
136
137 return (accept1(p, uap, retval, 1));
138 }
139 #else /* COMPAT_OLDSOCK */
140
141 #define accept1 accept
142 #endif
143
144 int
accept1(p,uap,retval,compat_43)145 accept1(p, uap, retval, compat_43)
146 struct proc *p;
147 register struct accept_args /* {
148 syscallarg(int) s;
149 syscallarg(caddr_t) name;
150 syscallarg(int *) anamelen;
151 } */ *uap;
152 register_t *retval;
153 int compat_43;
154 {
155 struct file *fp;
156 struct mbuf *nam;
157 int namelen, error, s, tmpfd;
158 register struct socket *so;
159
160 if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, anamelen),
161 (caddr_t)&namelen, sizeof (namelen))))
162 return (error);
163 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
164 return (error);
165 s = splnet();
166 so = (struct socket *)fp->f_data;
167 if ((so->so_options & SO_ACCEPTCONN) == 0) {
168 splx(s);
169 return (EINVAL);
170 }
171 if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
172 splx(s);
173 return (EWOULDBLOCK);
174 }
175 while (so->so_qlen == 0 && so->so_error == 0) {
176 if (so->so_state & SS_CANTRCVMORE) {
177 so->so_error = ECONNABORTED;
178 break;
179 }
180 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
181 netcon, 0)) {
182 splx(s);
183 return (error);
184 }
185 }
186 if (so->so_error) {
187 error = so->so_error;
188 so->so_error = 0;
189 splx(s);
190 return (error);
191 }
192 if (error = falloc(p, &fp, &tmpfd)) {
193 splx(s);
194 return (error);
195 }
196 *retval = tmpfd;
197 { struct socket *aso = so->so_q;
198 if (soqremque(aso, 1) == 0)
199 panic("accept");
200 so = aso;
201 }
202 fp->f_type = DTYPE_SOCKET;
203 fp->f_flag = FREAD|FWRITE;
204 fp->f_ops = &socketops;
205 fp->f_data = (caddr_t)so;
206 nam = m_get(M_WAIT, MT_SONAME);
207 (void) soaccept(so, nam);
208 if (SCARG(uap, name)) {
209 #ifdef COMPAT_OLDSOCK
210 if (compat_43)
211 mtod(nam, struct osockaddr *)->sa_family =
212 mtod(nam, struct sockaddr *)->sa_family;
213 #endif
214 if (namelen > nam->m_len)
215 namelen = nam->m_len;
216 /* SHOULD COPY OUT A CHAIN HERE */
217 if ((error = copyout(mtod(nam, caddr_t),
218 (caddr_t)SCARG(uap, name), (u_int)namelen)) == 0)
219 error = copyout((caddr_t)&namelen,
220 (caddr_t)SCARG(uap, anamelen),
221 sizeof (*SCARG(uap, anamelen)));
222 }
223 m_freem(nam);
224 splx(s);
225 return (error);
226 }
227
228 /* ARGSUSED */
229 int
connect(p,uap,retval)230 connect(p, uap, retval)
231 struct proc *p;
232 register struct connect_args /* {
233 syscallarg(int) s;
234 syscallarg(caddr_t) name;
235 syscallarg(int) namelen;
236 } */ *uap;
237 register_t *retval;
238 {
239 struct file *fp;
240 register struct socket *so;
241 struct mbuf *nam;
242 int error, s;
243
244 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
245 return (error);
246 so = (struct socket *)fp->f_data;
247 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
248 return (EALREADY);
249 if (error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
250 MT_SONAME))
251 return (error);
252 error = soconnect(so, nam);
253 if (error)
254 goto bad;
255 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
256 m_freem(nam);
257 return (EINPROGRESS);
258 }
259 s = splnet();
260 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
261 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
262 netcon, 0))
263 break;
264 if (error == 0) {
265 error = so->so_error;
266 so->so_error = 0;
267 }
268 splx(s);
269 bad:
270 so->so_state &= ~SS_ISCONNECTING;
271 m_freem(nam);
272 if (error == ERESTART)
273 error = EINTR;
274 return (error);
275 }
276
277 int
socketpair(p,uap,retval)278 socketpair(p, uap, retval)
279 struct proc *p;
280 register struct socketpair_args /* {
281 syscallarg(int) domain;
282 syscallarg(int) type;
283 syscallarg(int) protocol;
284 syscallarg(int *) rsv;
285 } */ *uap;
286 register_t *retval;
287 {
288 register struct filedesc *fdp = p->p_fd;
289 struct file *fp1, *fp2;
290 struct socket *so1, *so2;
291 int fd, error, sv[2];
292
293 if (error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
294 SCARG(uap, protocol)))
295 return (error);
296 if (error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
297 SCARG(uap, protocol)))
298 goto free1;
299 if (error = falloc(p, &fp1, &fd))
300 goto free2;
301 sv[0] = fd;
302 fp1->f_flag = FREAD|FWRITE;
303 fp1->f_type = DTYPE_SOCKET;
304 fp1->f_ops = &socketops;
305 fp1->f_data = (caddr_t)so1;
306 if (error = falloc(p, &fp2, &fd))
307 goto free3;
308 fp2->f_flag = FREAD|FWRITE;
309 fp2->f_type = DTYPE_SOCKET;
310 fp2->f_ops = &socketops;
311 fp2->f_data = (caddr_t)so2;
312 sv[1] = fd;
313 if (error = soconnect2(so1, so2))
314 goto free4;
315 if (SCARG(uap, type) == SOCK_DGRAM) {
316 /*
317 * Datagram socket connection is asymmetric.
318 */
319 if (error = soconnect2(so2, so1))
320 goto free4;
321 }
322 error = copyout((caddr_t)sv, (caddr_t)SCARG(uap, rsv),
323 2 * sizeof (int));
324 retval[0] = sv[0]; /* XXX ??? */
325 retval[1] = sv[1]; /* XXX ??? */
326 return (error);
327 free4:
328 ffree(fp2);
329 fdp->fd_ofiles[sv[1]] = 0;
330 free3:
331 ffree(fp1);
332 fdp->fd_ofiles[sv[0]] = 0;
333 free2:
334 (void)soclose(so2);
335 free1:
336 (void)soclose(so1);
337 return (error);
338 }
339
340 int
sendto(p,uap,retval)341 sendto(p, uap, retval)
342 struct proc *p;
343 register struct sendto_args /* {
344 syscallarg(int) s;
345 syscallarg(caddr_t) buf;
346 syscallarg(size_t) len;
347 syscallarg(int) flags;
348 syscallarg(caddr_t) to;
349 syscallarg(int) tolen;
350 } */ *uap;
351 register_t *retval;
352 {
353 struct msghdr msg;
354 struct iovec aiov;
355
356 msg.msg_name = SCARG(uap, to);
357 msg.msg_namelen = SCARG(uap, tolen);
358 msg.msg_iov = &aiov;
359 msg.msg_iovlen = 1;
360 msg.msg_control = 0;
361 #ifdef COMPAT_OLDSOCK
362 msg.msg_flags = 0;
363 #endif
364 aiov.iov_base = SCARG(uap, buf);
365 aiov.iov_len = SCARG(uap, len);
366 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
367 }
368
369 #ifdef COMPAT_OLDSOCK
370 int
compat_43_send(p,uap,retval)371 compat_43_send(p, uap, retval)
372 struct proc *p;
373 register struct compat_43_send_args /* {
374 syscallarg(int) s;
375 syscallarg(caddr_t) buf;
376 syscallarg(int) len;
377 syscallarg(int) flags;
378 } */ *uap;
379 register_t *retval;
380 {
381 struct msghdr msg;
382 struct iovec aiov;
383
384 msg.msg_name = 0;
385 msg.msg_namelen = 0;
386 msg.msg_iov = &aiov;
387 msg.msg_iovlen = 1;
388 aiov.iov_base = SCARG(uap, buf);
389 aiov.iov_len = SCARG(uap, len);
390 msg.msg_control = 0;
391 msg.msg_flags = 0;
392 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
393 }
394
395 #define MSG_COMPAT 0x8000
396 int
compat_43_sendmsg(p,uap,retval)397 compat_43_sendmsg(p, uap, retval)
398 struct proc *p;
399 register struct compat_43_sendmsg_args /* {
400 syscallarg(int) s;
401 syscallarg(caddr_t) msg;
402 syscallarg(int) flags;
403 } */ *uap;
404 register_t *retval;
405 {
406 struct msghdr msg;
407 struct iovec aiov[UIO_SMALLIOV], *iov;
408 int error;
409
410 if (error = copyin(SCARG(uap, msg), (caddr_t)&msg,
411 sizeof (struct omsghdr)))
412 return (error);
413 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
414 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
415 return (EMSGSIZE);
416 MALLOC(iov, struct iovec *,
417 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
418 M_WAITOK);
419 } else
420 iov = aiov;
421 if (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
422 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
423 goto done;
424 msg.msg_flags = MSG_COMPAT;
425 msg.msg_iov = iov;
426 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
427 done:
428 if (iov != aiov)
429 FREE(iov, M_IOV);
430 return (error);
431 }
432 #endif
433
434 int
sendmsg(p,uap,retval)435 sendmsg(p, uap, retval)
436 struct proc *p;
437 register struct sendmsg_args /* {
438 syscallarg(int) s;
439 syscallarg(caddr_t) msg;
440 syscallarg(int) flags;
441 } */ *uap;
442 register_t *retval;
443 {
444 struct msghdr msg;
445 struct iovec aiov[UIO_SMALLIOV], *iov;
446 int error;
447
448 if (error = copyin(SCARG(uap, msg), (caddr_t)&msg, sizeof (msg)))
449 return (error);
450 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
451 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
452 return (EMSGSIZE);
453 MALLOC(iov, struct iovec *,
454 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
455 M_WAITOK);
456 } else
457 iov = aiov;
458 if (msg.msg_iovlen &&
459 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
460 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
461 goto done;
462 msg.msg_iov = iov;
463 #ifdef COMPAT_OLDSOCK
464 msg.msg_flags = 0;
465 #endif
466 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
467 done:
468 if (iov != aiov)
469 FREE(iov, M_IOV);
470 return (error);
471 }
472
473 int
sendit(p,s,mp,flags,retsize)474 sendit(p, s, mp, flags, retsize)
475 register struct proc *p;
476 int s;
477 register struct msghdr *mp;
478 int flags;
479 register_t *retsize;
480 {
481 struct file *fp;
482 struct uio auio;
483 register struct iovec *iov;
484 register int i;
485 struct mbuf *to, *control;
486 int len, error;
487 #ifdef KTRACE
488 struct iovec *ktriov = NULL;
489 #endif
490
491 if (error = getsock(p->p_fd, s, &fp))
492 return (error);
493 auio.uio_iov = mp->msg_iov;
494 auio.uio_iovcnt = mp->msg_iovlen;
495 auio.uio_segflg = UIO_USERSPACE;
496 auio.uio_rw = UIO_WRITE;
497 auio.uio_procp = p;
498 auio.uio_offset = 0; /* XXX */
499 auio.uio_resid = 0;
500 iov = mp->msg_iov;
501 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
502 if (auio.uio_resid + iov->iov_len < auio.uio_resid)
503 return (EINVAL);
504 auio.uio_resid += iov->iov_len;
505 }
506 if (mp->msg_name) {
507 if (error = sockargs(&to, mp->msg_name, mp->msg_namelen,
508 MT_SONAME))
509 return (error);
510 } else
511 to = 0;
512 if (mp->msg_control) {
513 if (mp->msg_controllen < sizeof(struct cmsghdr)
514 #ifdef COMPAT_OLDSOCK
515 && mp->msg_flags != MSG_COMPAT
516 #endif
517 ) {
518 error = EINVAL;
519 goto bad;
520 }
521 if (error = sockargs(&control, mp->msg_control,
522 mp->msg_controllen, MT_CONTROL))
523 goto bad;
524 #ifdef COMPAT_OLDSOCK
525 if (mp->msg_flags == MSG_COMPAT) {
526 register struct cmsghdr *cm;
527
528 M_PREPEND(control, sizeof(*cm), M_WAIT);
529 if (control == 0) {
530 error = ENOBUFS;
531 goto bad;
532 } else {
533 cm = mtod(control, struct cmsghdr *);
534 cm->cmsg_len = control->m_len;
535 cm->cmsg_level = SOL_SOCKET;
536 cm->cmsg_type = SCM_RIGHTS;
537 }
538 }
539 #endif
540 } else
541 control = 0;
542 #ifdef KTRACE
543 if (KTRPOINT(p, KTR_GENIO)) {
544 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
545
546 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
547 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
548 }
549 #endif
550 len = auio.uio_resid;
551 if (error = sosend((struct socket *)fp->f_data, to, &auio,
552 (struct mbuf *)0, control, flags)) {
553 if (auio.uio_resid != len && (error == ERESTART ||
554 error == EINTR || error == EWOULDBLOCK))
555 error = 0;
556 if (error == EPIPE)
557 psignal(p, SIGPIPE);
558 }
559 if (error == 0)
560 *retsize = len - auio.uio_resid;
561 #ifdef KTRACE
562 if (ktriov != NULL) {
563 if (error == 0)
564 ktrgenio(p->p_tracep, s, UIO_WRITE,
565 ktriov, *retsize, error);
566 FREE(ktriov, M_TEMP);
567 }
568 #endif
569 bad:
570 if (to)
571 m_freem(to);
572 return (error);
573 }
574
575 #ifdef COMPAT_OLDSOCK
576 int
compat_43_recvfrom(p,uap,retval)577 compat_43_recvfrom(p, uap, retval)
578 struct proc *p;
579 struct recvfrom_args /* {
580 syscallarg(int) s;
581 syscallarg(caddr_t) buf;
582 syscallarg(size_t) len;
583 syscallarg(int) flags;
584 syscallarg(caddr_t) from;
585 syscallarg(int *) fromlenaddr;
586 } */ *uap;
587 register_t *retval;
588 {
589
590 SCARG(uap, flags) |= MSG_COMPAT;
591 return (recvfrom(p, uap, retval));
592 }
593 #endif
594
595 int
recvfrom(p,uap,retval)596 recvfrom(p, uap, retval)
597 struct proc *p;
598 register struct recvfrom_args /* {
599 syscallarg(int) s;
600 syscallarg(caddr_t) buf;
601 syscallarg(size_t) len;
602 syscallarg(int) flags;
603 syscallarg(caddr_t) from;
604 syscallarg(int *) fromlenaddr;
605 } */ *uap;
606 register_t *retval;
607 {
608 struct msghdr msg;
609 struct iovec aiov;
610 int error;
611
612 if (SCARG(uap, fromlenaddr)) {
613 if (error = copyin((caddr_t)SCARG(uap, fromlenaddr),
614 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen)))
615 return (error);
616 } else
617 msg.msg_namelen = 0;
618 msg.msg_name = SCARG(uap, from);
619 msg.msg_iov = &aiov;
620 msg.msg_iovlen = 1;
621 aiov.iov_base = SCARG(uap, buf);
622 aiov.iov_len = SCARG(uap, len);
623 msg.msg_control = 0;
624 msg.msg_flags = SCARG(uap, flags);
625 return (recvit(p, SCARG(uap, s), &msg,
626 (caddr_t)SCARG(uap, fromlenaddr), retval));
627 }
628
629 #ifdef COMPAT_OLDSOCK
630 int
compat_43_recv(p,uap,retval)631 compat_43_recv(p, uap, retval)
632 struct proc *p;
633 register struct compat_43_recv_args /* {
634 syscallarg(int) s;
635 syscallarg(caddr_t) buf;
636 syscallarg(int) len;
637 syscallarg(int) flags;
638 } */ *uap;
639 register_t *retval;
640 {
641 struct msghdr msg;
642 struct iovec aiov;
643
644 msg.msg_name = 0;
645 msg.msg_namelen = 0;
646 msg.msg_iov = &aiov;
647 msg.msg_iovlen = 1;
648 aiov.iov_base = SCARG(uap, buf);
649 aiov.iov_len = SCARG(uap, len);
650 msg.msg_control = 0;
651 msg.msg_flags = SCARG(uap, flags);
652 return (recvit(p, SCARG(uap, s), &msg, (caddr_t)0, retval));
653 }
654
655 /*
656 * Old recvmsg. This code takes advantage of the fact that the old msghdr
657 * overlays the new one, missing only the flags, and with the (old) access
658 * rights where the control fields are now.
659 */
660 int
compat_43_recvmsg(p,uap,retval)661 compat_43_recvmsg(p, uap, retval)
662 struct proc *p;
663 register struct compat_43_recvmsg_args /* {
664 syscallarg(int) s;
665 syscallarg(struct omsghdr *) msg;
666 syscallarg(int) flags;
667 } */ *uap;
668 register_t *retval;
669 {
670 struct msghdr msg;
671 struct iovec aiov[UIO_SMALLIOV], *iov;
672 int error;
673
674 if (error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&msg,
675 sizeof (struct omsghdr)))
676 return (error);
677 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
678 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
679 return (EMSGSIZE);
680 MALLOC(iov, struct iovec *,
681 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
682 M_WAITOK);
683 } else
684 iov = aiov;
685 msg.msg_flags = SCARG(uap, flags) | MSG_COMPAT;
686 if (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
687 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
688 goto done;
689 msg.msg_iov = iov;
690 error = recvit(p, SCARG(uap, s), &msg,
691 (caddr_t)&SCARG(uap, msg)->msg_namelen, retval);
692
693 if (msg.msg_controllen && error == 0)
694 error = copyout((caddr_t)&msg.msg_controllen,
695 (caddr_t)&SCARG(uap, msg)->msg_accrightslen, sizeof (int));
696 done:
697 if (iov != aiov)
698 FREE(iov, M_IOV);
699 return (error);
700 }
701 #endif
702
703 int
recvmsg(p,uap,retval)704 recvmsg(p, uap, retval)
705 struct proc *p;
706 register struct recvmsg_args /* {
707 syscallarg(int) s;
708 syscallarg(struct msghdr *) msg;
709 syscallarg(int) flags;
710 } */ *uap;
711 register_t *retval;
712 {
713 struct msghdr msg;
714 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
715 register int error;
716
717 if (error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&msg,
718 sizeof (msg)))
719 return (error);
720 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
721 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
722 return (EMSGSIZE);
723 MALLOC(iov, struct iovec *,
724 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
725 M_WAITOK);
726 } else
727 iov = aiov;
728 #ifdef COMPAT_OLDSOCK
729 msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
730 #else
731 msg.msg_flags = SCARG(uap, flags);
732 #endif
733 uiov = msg.msg_iov;
734 msg.msg_iov = iov;
735 if (error = copyin((caddr_t)uiov, (caddr_t)iov,
736 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
737 goto done;
738 if ((error = recvit(p, SCARG(uap, s), &msg, (caddr_t)0, retval)) == 0) {
739 msg.msg_iov = uiov;
740 error = copyout((caddr_t)&msg, (caddr_t)SCARG(uap, msg),
741 sizeof(msg));
742 }
743 done:
744 if (iov != aiov)
745 FREE(iov, M_IOV);
746 return (error);
747 }
748
749 int
recvit(p,s,mp,namelenp,retsize)750 recvit(p, s, mp, namelenp, retsize)
751 register struct proc *p;
752 int s;
753 register struct msghdr *mp;
754 caddr_t namelenp;
755 register_t *retsize;
756 {
757 struct file *fp;
758 struct uio auio;
759 register struct iovec *iov;
760 register int i;
761 int len, error;
762 struct mbuf *from = 0, *control = 0;
763 #ifdef KTRACE
764 struct iovec *ktriov = NULL;
765 #endif
766
767 if (error = getsock(p->p_fd, s, &fp))
768 return (error);
769 auio.uio_iov = mp->msg_iov;
770 auio.uio_iovcnt = mp->msg_iovlen;
771 auio.uio_segflg = UIO_USERSPACE;
772 auio.uio_rw = UIO_READ;
773 auio.uio_procp = p;
774 auio.uio_offset = 0; /* XXX */
775 auio.uio_resid = 0;
776 iov = mp->msg_iov;
777 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
778 if (auio.uio_resid + iov->iov_len < auio.uio_resid)
779 return (EINVAL);
780 auio.uio_resid += iov->iov_len;
781 }
782 #ifdef KTRACE
783 if (KTRPOINT(p, KTR_GENIO)) {
784 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
785
786 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
787 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
788 }
789 #endif
790 len = auio.uio_resid;
791 if (error = soreceive((struct socket *)fp->f_data, &from, &auio,
792 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
793 &mp->msg_flags)) {
794 if (auio.uio_resid != len && (error == ERESTART ||
795 error == EINTR || error == EWOULDBLOCK))
796 error = 0;
797 }
798 #ifdef KTRACE
799 if (ktriov != NULL) {
800 if (error == 0)
801 ktrgenio(p->p_tracep, s, UIO_READ,
802 ktriov, len - auio.uio_resid, error);
803 FREE(ktriov, M_TEMP);
804 }
805 #endif
806 if (error)
807 goto out;
808 *retsize = len - auio.uio_resid;
809 if (mp->msg_name) {
810 len = mp->msg_namelen;
811 if (len <= 0 || from == 0)
812 len = 0;
813 else {
814 #ifdef COMPAT_OLDSOCK
815 if (mp->msg_flags & MSG_COMPAT)
816 mtod(from, struct osockaddr *)->sa_family =
817 mtod(from, struct sockaddr *)->sa_family;
818 #endif
819 if (len > from->m_len)
820 len = from->m_len;
821 /* else if len < from->m_len ??? */
822 if (error = copyout(mtod(from, caddr_t),
823 (caddr_t)mp->msg_name, (unsigned)len))
824 goto out;
825 }
826 mp->msg_namelen = len;
827 if (namelenp &&
828 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
829 #ifdef COMPAT_OLDSOCK
830 if (mp->msg_flags & MSG_COMPAT)
831 error = 0; /* old recvfrom didn't check */
832 else
833 #endif
834 goto out;
835 }
836 }
837 if (mp->msg_control) {
838 #ifdef COMPAT_OLDSOCK
839 /*
840 * We assume that old recvmsg calls won't receive access
841 * rights and other control info, esp. as control info
842 * is always optional and those options didn't exist in 4.3.
843 * If we receive rights, trim the cmsghdr; anything else
844 * is tossed.
845 */
846 if (control && mp->msg_flags & MSG_COMPAT) {
847 if (mtod(control, struct cmsghdr *)->cmsg_level !=
848 SOL_SOCKET ||
849 mtod(control, struct cmsghdr *)->cmsg_type !=
850 SCM_RIGHTS) {
851 mp->msg_controllen = 0;
852 goto out;
853 }
854 control->m_len -= sizeof (struct cmsghdr);
855 control->m_data += sizeof (struct cmsghdr);
856 }
857 #endif
858 len = mp->msg_controllen;
859 if (len <= 0 || control == 0)
860 len = 0;
861 else {
862 if (len >= control->m_len)
863 len = control->m_len;
864 else
865 mp->msg_flags |= MSG_CTRUNC;
866 error = copyout((caddr_t)mtod(control, caddr_t),
867 (caddr_t)mp->msg_control, (unsigned)len);
868 }
869 mp->msg_controllen = len;
870 }
871 out:
872 if (from)
873 m_freem(from);
874 if (control)
875 m_freem(control);
876 return (error);
877 }
878
879 /* ARGSUSED */
880 int
shutdown(p,uap,retval)881 shutdown(p, uap, retval)
882 struct proc *p;
883 register struct shutdown_args /* {
884 syscallarg(int) s;
885 syscallarg(int) how;
886 } */ *uap;
887 register_t *retval;
888 {
889 struct file *fp;
890 int error;
891
892 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
893 return (error);
894 return (soshutdown((struct socket *)fp->f_data, SCARG(uap, how)));
895 }
896
897 /* ARGSUSED */
898 int
setsockopt(p,uap,retval)899 setsockopt(p, uap, retval)
900 struct proc *p;
901 register struct setsockopt_args /* {
902 syscallarg(int) s;
903 syscallarg(int) level;
904 syscallarg(int) name;
905 syscallarg(caddr_t) val;
906 syscallarg(int) valsize;
907 } */ *uap;
908 register_t *retval;
909 {
910 struct file *fp;
911 struct mbuf *m = NULL;
912 int error;
913
914 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
915 return (error);
916 if (SCARG(uap, valsize) > MLEN)
917 return (EINVAL);
918 if (SCARG(uap, val)) {
919 m = m_get(M_WAIT, MT_SOOPTS);
920 if (m == NULL)
921 return (ENOBUFS);
922 if (error = copyin(SCARG(uap, val), mtod(m, caddr_t),
923 (u_int)SCARG(uap, valsize))) {
924 (void) m_free(m);
925 return (error);
926 }
927 m->m_len = SCARG(uap, valsize);
928 }
929 return (sosetopt((struct socket *)fp->f_data, SCARG(uap, level),
930 SCARG(uap, name), m));
931 }
932
933 /* ARGSUSED */
934 int
getsockopt(p,uap,retval)935 getsockopt(p, uap, retval)
936 struct proc *p;
937 register struct getsockopt_args /* {
938 syscallarg(int) s;
939 syscallarg(int) level;
940 syscallarg(int) name;
941 syscallarg(caddr_t) val;
942 syscallarg(int *) avalsize;
943 } */ *uap;
944 register_t *retval;
945 {
946 struct file *fp;
947 struct mbuf *m = NULL;
948 int valsize, error;
949
950 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
951 return (error);
952 if (SCARG(uap, val)) {
953 if (error = copyin((caddr_t)SCARG(uap, avalsize),
954 (caddr_t)&valsize, sizeof (valsize)))
955 return (error);
956 } else
957 valsize = 0;
958 if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level),
959 SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
960 m != NULL) {
961 if (valsize > m->m_len)
962 valsize = m->m_len;
963 error = copyout(mtod(m, caddr_t), SCARG(uap, val),
964 (u_int)valsize);
965 if (error == 0)
966 error = copyout((caddr_t)&valsize,
967 (caddr_t)SCARG(uap, avalsize), sizeof (valsize));
968 }
969 if (m != NULL)
970 (void) m_free(m);
971 return (error);
972 }
973
974 /* ARGSUSED */
975 int
pipe(p,uap,retval)976 pipe(p, uap, retval)
977 struct proc *p;
978 void *uap;
979 register_t *retval;
980 {
981 register struct filedesc *fdp = p->p_fd;
982 struct file *rf, *wf;
983 struct socket *rso, *wso;
984 int fd, error;
985
986 if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0))
987 return (error);
988 if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0))
989 goto free1;
990 if (error = falloc(p, &rf, &fd))
991 goto free2;
992 retval[0] = fd;
993 rf->f_flag = FREAD;
994 rf->f_type = DTYPE_SOCKET;
995 rf->f_ops = &socketops;
996 rf->f_data = (caddr_t)rso;
997 if (error = falloc(p, &wf, &fd))
998 goto free3;
999 wf->f_flag = FWRITE;
1000 wf->f_type = DTYPE_SOCKET;
1001 wf->f_ops = &socketops;
1002 wf->f_data = (caddr_t)wso;
1003 retval[1] = fd;
1004 if (error = unp_connect2(wso, rso))
1005 goto free4;
1006 return (0);
1007 free4:
1008 ffree(wf);
1009 fdp->fd_ofiles[retval[1]] = 0;
1010 free3:
1011 ffree(rf);
1012 fdp->fd_ofiles[retval[0]] = 0;
1013 free2:
1014 (void)soclose(wso);
1015 free1:
1016 (void)soclose(rso);
1017 return (error);
1018 }
1019
1020 /*
1021 * Get socket name.
1022 */
1023 #ifdef COMPAT_OLDSOCK
1024 int
getsockname(p,uap,retval)1025 getsockname(p, uap, retval)
1026 struct proc *p;
1027 struct getsockname_args /* {
1028 syscallarg(int) fdes;
1029 syscallarg(caddr_t) asa;
1030 syscallarg(int *) alen;
1031 } */ *uap;
1032 register_t *retval;
1033 {
1034
1035 return (getsockname1(p, uap, retval, 0));
1036 }
1037
1038 int
compat_43_getsockname(p,uap,retval)1039 compat_43_getsockname(p, uap, retval)
1040 struct proc *p;
1041 struct getsockname_args /* {
1042 syscallarg(int) fdes;
1043 syscallarg(caddr_t) asa;
1044 syscallarg(int *) alen;
1045 } */ *uap;
1046 register_t *retval;
1047 {
1048
1049 return (getsockname1(p, uap, retval, 1));
1050 }
1051 #else /* COMPAT_OLDSOCK */
1052
1053 #define getsockname1 getsockname
1054 #endif
1055
1056 /* ARGSUSED */
1057 int
getsockname1(p,uap,retval,compat_43)1058 getsockname1(p, uap, retval, compat_43)
1059 struct proc *p;
1060 register struct getsockname_args /* {
1061 syscallarg(int) fdes;
1062 syscallarg(caddr_t) asa;
1063 syscallarg(int *) alen;
1064 } */ *uap;
1065 register_t *retval;
1066 int compat_43;
1067 {
1068 struct file *fp;
1069 register struct socket *so;
1070 struct mbuf *m;
1071 int len, error;
1072
1073 if (error = getsock(p->p_fd, SCARG(uap, fdes), &fp))
1074 return (error);
1075 if (error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len,
1076 sizeof (len)))
1077 return (error);
1078 so = (struct socket *)fp->f_data;
1079 m = m_getclr(M_WAIT, MT_SONAME);
1080 if (m == NULL)
1081 return (ENOBUFS);
1082 if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0))
1083 goto bad;
1084 if (len > m->m_len)
1085 len = m->m_len;
1086 #ifdef COMPAT_OLDSOCK
1087 if (compat_43)
1088 mtod(m, struct osockaddr *)->sa_family =
1089 mtod(m, struct sockaddr *)->sa_family;
1090 #endif
1091 error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), (u_int)len);
1092 if (error == 0)
1093 error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
1094 sizeof (len));
1095 bad:
1096 m_freem(m);
1097 return (error);
1098 }
1099
1100 /*
1101 * Get name of peer for connected socket.
1102 */
1103 #ifdef COMPAT_OLDSOCK
1104 int
getpeername(p,uap,retval)1105 getpeername(p, uap, retval)
1106 struct proc *p;
1107 struct getpeername_args /* {
1108 syscallarg(int) fdes;
1109 syscallarg(caddr_t) asa;
1110 syscallarg(int *) alen;
1111 } */ *uap;
1112 register_t *retval;
1113 {
1114
1115 return (getpeername1(p, uap, retval, 0));
1116 }
1117
1118 int
compat_43_getpeername(p,uap,retval)1119 compat_43_getpeername(p, uap, retval)
1120 struct proc *p;
1121 struct getpeername_args /* {
1122 syscallarg(int) fdes;
1123 syscallarg(caddr_t) asa;
1124 syscallarg(int *) alen;
1125 } */ *uap;
1126 register_t *retval;
1127 {
1128
1129 return (getpeername1(p, uap, retval, 1));
1130 }
1131 #else /* COMPAT_OLDSOCK */
1132
1133 #define getpeername1 getpeername
1134 #endif
1135
1136 /* ARGSUSED */
1137 int
getpeername1(p,uap,retval,compat_43)1138 getpeername1(p, uap, retval, compat_43)
1139 struct proc *p;
1140 register struct getpeername_args /* {
1141 syscallarg(int) fdes;
1142 syscallarg(caddr_t) asa;
1143 syscallarg(int *) alen;
1144 } */ *uap;
1145 register_t *retval;
1146 int compat_43;
1147 {
1148 struct file *fp;
1149 register struct socket *so;
1150 struct mbuf *m;
1151 int len, error;
1152
1153 if (error = getsock(p->p_fd, SCARG(uap, fdes), &fp))
1154 return (error);
1155 so = (struct socket *)fp->f_data;
1156 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1157 return (ENOTCONN);
1158 if (error =
1159 copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len)))
1160 return (error);
1161 m = m_getclr(M_WAIT, MT_SONAME);
1162 if (m == NULL)
1163 return (ENOBUFS);
1164 if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0))
1165 goto bad;
1166 if (len > m->m_len)
1167 len = m->m_len;
1168 #ifdef COMPAT_OLDSOCK
1169 if (compat_43)
1170 mtod(m, struct osockaddr *)->sa_family =
1171 mtod(m, struct sockaddr *)->sa_family;
1172 #endif
1173 if (error =
1174 copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), (u_int)len))
1175 goto bad;
1176 error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen), sizeof (len));
1177 bad:
1178 m_freem(m);
1179 return (error);
1180 }
1181
1182 int
sockargs(mp,buf,buflen,type)1183 sockargs(mp, buf, buflen, type)
1184 struct mbuf **mp;
1185 caddr_t buf;
1186 int buflen, type;
1187 {
1188 register struct sockaddr *sa;
1189 register struct mbuf *m;
1190 int error;
1191
1192 if ((u_int)buflen > MLEN) {
1193 #ifdef COMPAT_OLDSOCK
1194 if (type == MT_SONAME && (u_int)buflen <= 112)
1195 buflen = MLEN; /* unix domain compat. hack */
1196 else
1197 #endif
1198 return (EINVAL);
1199 }
1200 m = m_get(M_WAIT, type);
1201 if (m == NULL)
1202 return (ENOBUFS);
1203 m->m_len = buflen;
1204 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1205 if (error) {
1206 (void) m_free(m);
1207 return (error);
1208 }
1209 *mp = m;
1210 if (type == MT_SONAME) {
1211 sa = mtod(m, struct sockaddr *);
1212
1213 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1214 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1215 sa->sa_family = sa->sa_len;
1216 #endif
1217 sa->sa_len = buflen;
1218 }
1219 return (0);
1220 }
1221
1222 int
getsock(fdp,fdes,fpp)1223 getsock(fdp, fdes, fpp)
1224 struct filedesc *fdp;
1225 int fdes;
1226 struct file **fpp;
1227 {
1228 register struct file *fp;
1229
1230 if ((unsigned)fdes >= fdp->fd_nfiles ||
1231 (fp = fdp->fd_ofiles[fdes]) == NULL)
1232 return (EBADF);
1233 if (fp->f_type != DTYPE_SOCKET)
1234 return (ENOTSOCK);
1235 *fpp = fp;
1236 return (0);
1237 }
1238