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