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